Home c++ How to properly convey the function arguments in CreateThread

How to properly convey the function arguments in CreateThread

Author

Date

Category

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:

  1. Custom data can be transmitted by an opaque void * pointer, which is transmitted by the fourth argument in CreateThread , and then prohibited in the flow procedure.
  2. 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 .
  3. 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 .
  4. typical error is to ignore the values ​​returned by WinAPI features.
  5. typical error is to ignore the wait for the completion of the stream.
  6. typical error is to ignore the need to close the flow descriptor.
  7. 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.

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions