Hello I’m interested in how to transfer the arguments of the function transmitted in createethread
I use createethread (null, 0, lpthread_start_routine (func), null, 0, null)
I realized that I need to use threadproc
But I absolutely do not understand how to work with it, I would be very grateful if you led an example
Answer 1, Authority 100%
4 The parameter just receives a pointer to the data you need for stream. Let’s try the usual int there (code is a bit not for industrial use, but only for understanding)
# include & lt; iostream & gt;
#Include & lt; Windows.h & gt;
Using Namespace STD;
DWORD WINAPI MYTHREAD (Void * P)
{
int loop = (int) p; // Return Type Back Back
for (int i = 0; i & lt; loop; ++ i)
{
COUT & LT; & LT; I;
SLEEP (1);
}
Return 0;
}
Int Main (int argc, char * argv [])
{
int loop = 7; // Our parameter
CreateThread (0,4096, Mythread, (void *) Loop, 0, NULL);
// SAY SAFE AND RESIDENT ^^^^^^^^^^^^
For (int i = 0; i & lt; 20; ++ i)
{
COUT & LT; & LT; '-';
SLEEP (1);
}
}
looks wild, but it is also void *
. In the operating code, this parameter transmits a pointer to any structure created dynamically (if it is a pointer to the structure on the stack, then you need to worry about what would flow “live less than before going out of the caller”. In the case of a dynamic structure, you also need decide who and when to clean memory. There are such options:
- Flow will be cleaned (at the beginning of its work or at the end)
- flow in this structure will leave “its calculations”, and the caller will pick them up.
- Java-Style – Operations for us will subduct memory.
In general, the first option looks somewhere so.
# include & lt; iostream & gt;
#Include & lt; String & GT;
#Include & lt; Windows.h & gt;
Using Namespace STD;
// This is a structure for communication
Struct MyData.
{
int loop;
String Message;
};
DWORD WINAPI MYTHREAD (Void * P)
{
MyData * d = (MyData *) P; // Convert the pointer to the correct
For (int i = 0; i & lt; D- & gt; Loop; ++ i)
{
COUT & LT; & LT; D- & GT; Message & LT; & LT; "" & lt; & lt; I;
SLEEP (1);
}
DELETE D; // Clean when we do not need it
Return 0;
}
Int Main (int argc, char * argv [])
{
MyData * d = New MyData {7, "Hello"}; // Create an instance for work
CreateThread (0,4096, Mythread, (void *) d, 0, null);
For (int i = 0; i & lt; 20; ++ i)
{
COUT & LT; & LT; '-';
SLEEP (1);
}
}
Of course, this code should be submitted all sorts of checks that the flow has been created and similar, but in general is already a working code.
Answer 2, Authority 67%
Well, Here is an example , how to call it (simplified, without checks). Immediately the second example, how to do this, without bothering work with the API, but only with C++ products.
dword winpi thread1 (void *)
{
For (int i = 0; i & lt; 20; ++ i)
{
COUT & LT; & LT; I;
SLEEP (10);
}
Return 0;
}
void thread2 ()
{
For (int i = 0; i & lt; 20; ++ i)
{
COUT & LT; & LT; Char ('A' + I);
SLEEP (10);
}
}
INT MAIN ([[Maybe_Unused]] int argc,
[[Maybe_Unused]] Const Char * ArgV [])
{
CreateThread (0.4096, Thread1,0,0, NULL);
Thread Th (Thread2);
th.detach ();
For (int i = 0; i & lt; 20; ++ i)
{
COUT & LT; & LT; '-';
SLEEP (10);
}
}
can use what more like đŸ™‚
Answer 3
Here is a more or less full example:
# include & lt; windows.h & gt;
#Include & lt; Exception & gt;
#Include & lt; iostream & gt;
#Include & lt; Memory & gt;
#Include & lt; Cassert & GT;
#Include & lt; Cstdlib & gt;
#Include & lt; Cstddef & gt;
Struct.
T_THREADCONTEXT.
{
char const * psz_message;
:: STD :: EXCEPTION_PTR P_EXCEPTION;
};
DWORD WINAPI.
Thread_Proc (LPVoid Const Param) NOEXCEPT
{
ASSERT (Param);
DWORD EXIT_CODE {ERROR_INVALID_FUNCTION};
AUTO & AMP; CONTEXT {* STATIC_CAST & LT; T_THREADCONTEXT * & GT; (Param)};
Assert (context.psz_message);
Try.
{
// Do Some Work ...
:: STD :: COUT & LT; & LT; context.psz_message & lt; & lt; :: STD :: ENDL;
exit_code = error_success;
}
Catch (...)
{
// INTERSEPT EXCEPTION SO IT CAN BE INSPECTED IN PARENT THREAD
context.p_exception = :: STD :: CURRENT_EXCEPTION ();
EXIT_CODE = ERROR_INVALID_FUNCTION;
}
if (Still_Active == EXIT_CODE)
{
EXIT_CODE = ERROR_INVALID_FUNCTION;
}
RETURN EXIT_CODE;
}
int.
Main ([[Maybe_Unused]] int const argc, [[maybe_unused]] char const * const * const pp_args)
{
IN EXIT_CODE {EXIT_FAILURE};
Try.
{
Auto Const & Amp; psz_command {pp_args [0]};
:: T_THREADCONTEXT CONTEXT {PSZ_COMMAND};
Lpsecurity_attributes p_security_attributes {}; // NullPTR - Default Security
DWORD STACK_SIZE {}; // 0 - Default
DWORD FLAGS {}; // 0 - Default (Create Thread and Run It Immediately)
DWORD Thread_ID {};
Auto Const H_Thread.
{
:: CreateThread.
(
P_Security_attributes.
, stack_size
, :: std :: Addressof (:: thread_proc)
, Static_Cast & LT; lpvoid & gt; (:: std :: Addressof (Context))
, Flags.
:: STD :: Addressof (Thread_ID) // May Be NullPTR
)
};
if (not h_thread)
{
Auto Const Last_error {:: GetLastterror ()};
// Deal With Error ...
}
ELSE.
{
Auto Const Wait_Result {:: WaitForSingleObject (H_Thread, Infinite)};
if (wait_object_0! = Wait_Result)
{
Auto Const Last_error {:: GetLastterror ()};
// Error Here IS Most Likely Fatal ...
}
ELSE.
{
If (not :: Closehandle (H_Thread))
{
Auto Const Last_error {:: GetLastterror ()};
// Error Here IS Most Likely Fatal ...
}
ELSE.
{
// INSPECT EXCEPTION OCCURRED IN CHILD THREAD
if (context.p_exception)
{
:: STD :: RETHROW_EXCEPTION (CONTEXT.P_EXCEPTION);
}
EXIT_CODE = EXIT_SUCCESS;
}
}
}
}
Catch (...)
{
EXIT_CODE = EXIT_FAILURE;
}
RETURN EXIT_CODE;
}
Explanations:
- Custom data can be transmitted by an opaque
void *
pointer, which is transmitted by the fourth argument inCreateThread
, and then prohibited in the flow procedure. - flow procedure, as different other from WinAPI, is obliged to avoid translating C++ exceptions across the boundaries of the language. Therefore, it makes sense to declare as
noexcept
, and arising exclusions to intercept and either immediately process, or transfer to the main stream to process via:: std :: exception_ptr
. - The value returning the flow procedure may be arbitrary, however it makes sense to use Windows error codes. The only exception – as a return code should not be used
Still_Active
. - typical error is to ignore the values ​​returned by WinAPI features.
- typical error is to ignore the wait for the completion of the stream.
- typical error is to ignore the need to close the flow descriptor.
- Compared to the library class
:: std :: thread
, the creation of streams through WinAPI can be justified when you want to set the desired stack size or set security attributes.