@SpaceWorm
A LPTHREAD_START_ROUTINE cast like that should never be used with CreateThread, not even in a toy program.
If I remove the cast I get
error C2664: 'CreateThread' : cannot convert parameter 3 from
'DWORD (__cdecl *)(void)' to 'LPTHREAD_START_ROUTINE |
An error, not a warning!
This is the right way to code it is (inc. two stylistic tweaks):
1 2 3 4 5 6 7 8 9 10 11 12 13
|
#include<Windows.h>
#include<iostream>
DWORD WINAPI hello(void* pv) // can also use LPVOID
{
std::cout<<"Thread";
return 0;
}
int main()
{
CreateThread(NULL,0,hello,NULL,0,NULL);
std::cin.get();
return 0;
}
|
(For some reason people frequently use LPVOID and void* interchangeably, but not DWORD. And using NULL makes it cleared it's a pointer; returning 0 from main is a good habit (even though the compiler adds "return 0;" if you're too lazy to do so.)
You should never cast a function pointer (unless forced to!) as you can cause problems (note: some info is included for passing, less experienced readers.)
- First of all, your saying this function takes 1 parameter, when it doesn't, so the wrong number of parameter will be pucsed onto the stack when it calls.
- Then you're saying it's a __stdcall function (WINAPI is a #define of __stdcall) when it's __cdecl (usually, this is the default for most C++ and C compilers), so the stack clean up will be messed up.
Andy
PS A more complete, illustrative example:
Edit Also see Microdsoft example in: "Creating Threads"
http://msdn.microsoft.com/en-us/library/windows/desktop/ms682516%28v=vs.85%29.aspx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
|
#include<windows.h>
#include<iostream>
// Recovers user data (number of loops wanted)
// from start parameter and runs loop.
//
// NOTE this code is passing the address of a local variable
// in main. It is safe to do so here as main() is waiting for this
// thread and so the variable will be valid (i.e. exist) for the
// whole lifetime of the thread.
//
// In the general case, memory for the thread parameter
// should be allocated on the heap using new or malloc and then
// left for the thread to delete when it's done with the data
// (with delete or free.) Or a similar mechanism.
DWORD WINAPI hello_thread_routine(void* param)
{
const int loop_period_msecs = 250;
// recover data from thread parameter
const int loop_count = *((const long*)param);
for(int i = 0; i < loop_count; ++i)
{
std::cout << "Thread : loop #" << (i + 1)
<< " of " << loop_count << std::endl;
Sleep(loop_period_msecs);
}
std::cout << "Thread : done" << std::endl;
return 0;
}
// main creates thread suspended and then uses ResumeThread
// to prevent output from main and thread from getting mixed up.
// Threads are often created non-suspended.
int main()
{
const int loop_count = 10;
std::cout << "main : Create thread" << std::endl;
HANDLE hThread = CreateThread( NULL, // NULL = use default security
0, // 0 = use default stack size
hello_thread_routine,
(LPVOID)&loop_count, // start param
CREATE_SUSPENDED, // flags
NULL ); // don't want thread id
std::cout << "main : Wait for thread" << std::endl;
ResumeThread(hThread); // see note above
WaitForSingleObject(hThread, INFINITE);
std::cout << "main : Close thread handle" << std::endl;
CloseHandle(hThread); // should close handle
std::cout << "main : <return> to continue...";
std::cin.get();
return 0;
}
|