Conversion error in CreateThread

2019-08-19 00:06发布

I have a weird bug when I try to use the CreateThread function. Here's my code:

HANDLE threads[3];  //threads[0] is printer, threads[1] is receiver, [2] is serverconn
    DWORD  printer_id,  receiver_id, serverconn_id;
    if(
                      ((threads [0] = CreateThread(NULL, 0, printer_thread,    (LPVOID) thread_args, 0, &printer_id)) == NULL) ||
        ((recv_thread = threads [1] = CreateThread(NULL, 0, receiver_thread,   (LPVOID) thread_args, 0, &receiver_id)) == NULL) ||
                      ((threads [2] = CreateThread(NULL, 0, serverconn_thread, (LPVOID) thread_args, 0, &serverconn_id)) == NULL)
    )
    {
        IO_print_line("Initialization error");
        return FALSE;
    }

printer_thread, receiver_thread and serverconn_thread are functions defined like this:

int serverconn_thread(LPVOID args);

The Visual Studio compiler gives me this error:

Error   C2440   'function': cannot convert from 'int (__cdecl *)(LPVOID)' to 'LPTHREAD_START_ROUTINE'

And I really don't get it since I think I've done exactly what the official documentation suggests.

And no, changing the thread functions' return type to DWORD doesn't solve anything, the error only changes to:

Error   C2440   'function': cannot convert from 'DWORD (__cdecl *)(LPVOID)' to 'LPTHREAD_START_ROUTINE'

Weird thing is if I change it like this:

if(
                      ((threads [0] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &printer_thread,    (LPVOID) thread_args, 0, &printer_id)) == NULL) ||
        ((recv_thread = threads [1] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &receiver_thread,   (LPVOID) thread_args, 0, &receiver_id)) == NULL) ||
                      ((threads [2] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) &serverconn_thread, (LPVOID) thread_args, 0, &serverconn_id)) == NULL)
    )

With a forced cast, compiler is ok but I don't think it's a good idea to brute-force it this way. How do I fix this?

1条回答
该账号已被封号
2楼-- · 2019-08-19 00:26

You are NOT following the official documentation when declaring your thread functions.

Your original declarations were using int as the return value, and __cdecl (implicitly) as the calling convention. When you changed the return value to DWORD, you did not change the calling convention.

However, the documentation clearly shows the correct declaration:

DWORD WINAPI ThreadProc(
  _In_ LPVOID lpParameter
);

DWORD is an unsigned long, and WINAPI is a macro that maps to the __stdcall calling convention (see Windows Data Types).

So, the correct declaration of your functions would be:

unsigned long __stdcall printer_thread(void *args);
unsigned long __stdcall receiver_thread(void *args);
unsigned long __stdcall serverconn_thread(void *args);

However, since CreateThread() takes an LPTHREAD_START_ROUTINE as input, which is declared as DWORD (WINAPI*)(LPVOID) (see the actual declaration in winbase.h), you should declare your functions to match:

DWORD WINAPI printer_thread(LPVOID args);
DWORD WINAPI receiver_thread(LPVOID args);
DWORD WINAPI serverconn_thread(LPVOID args);
查看更多
登录 后发表回答