Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do thread functions need to be declared as '__cdecl'?

Sample code that shows how to create threads using MFC declares the thread function as both static and __cdecl. Why is the latter required? Boost threads don't bother with this convention, so is it just an anachronism?

For example (MFC):

static __cdecl UINT MyFunc(LPVOID pParam)
{
...
}

CWinThread* pThread = AfxBeginThread(MyFunc, ...);

Whereas Boost:

static void func()
{
...
}

boost::thread t;
t.create(&func);

(the code samples might not be 100% correct as I am nowhere near an IDE).

What is the point of __cdecl? How does it help when creating threads?

like image 464
Rob Avatar asked Oct 04 '08 14:10

Rob


People also ask

What is __ Cdecl in C++?

__cdecl is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code.

What does Cdecl stand for?

The cdecl (C Declaration) calling convention is usually the default calling convention for x86 C compilers.

What is pthread_ t in C?

pthread_t is the data type used to uniquely identify a thread. It is returned by pthread_create() and used by the application in function calls that require a thread identifier. The thread is created running start_routine, with arg as the only argument.

Does Pthread create start the thread?

The pthread_create() function starts a new thread in the calling process. The new thread starts execution by invoking start_routine(); arg is passed as the sole argument of start_routine().


2 Answers

__cdecl tells the compiler to use the C calling convention (as opposed to the stdcall, fastcall or whatever other calling convention your compiler supports). I believe, VC++ uses stdcall by default.

The calling convention affects things such as how arguments are pushed onto the stack (or registers, in the case of fastcall) and who pops arguments off the stack (caller or callee).

In the case of Boost. I believe it uses template specialization to figure out the appropriate function type and calling convention.

like image 61
Ferruccio Avatar answered Sep 28 '22 18:09

Ferruccio


Look at the prototype for AfxBeginThread():

CWinThread* AfxBeginThread(
   AFX_THREADPROC pfnThreadProc,
   LPVOID pParam,
   int nPriority = THREAD_PRIORITY_NORMAL,
   UINT nStackSize = 0,
   DWORD dwCreateFlags = 0,
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL 
);

AFX_THREADPROC is a typedef for UINT(AFX_CDECL*)(LPVOID). When you pass a function to AfxBeginThread(), it must match that prototype, including the calling convention.

The MSDN pages on __cdecl and __stdcall (as well as __fastcall and __thiscall) explain the pros and cons of each calling convention.

The boost::thread constructor uses templates to allow you to pass a function pointer or callable function object, so it doesn't have the same restrictions as MFC.

like image 38
bk1e Avatar answered Sep 28 '22 19:09

bk1e