I want a homegrown version of C++11's std::thread. My motivation is to avoid manual memory management of the arguments passed to the thread function. I'm restricted to C++98. I want better type safety than what's available in the POSIX and Win32 thread APIs.

Two notes:

1. I can't think of a way to avoid a heap allocation for the thunk argument. The thread instance could be deleted before the thunk has a chance to construct its arguments. I suppose I could wait on an event in the constructor signaled by thunk() once the thread is in a 'ready' state, but that seems horrible.
2. I'm not too concerned about exception safety as exceptions are disabled for most of this C++ codebase.

/* There is a portable thread implementation in C available already */
{
}

#define PORTABLE_THREAD_FUNC_DECL unsigned int __cdecl **OR**

{
WaitForSingleObject()
}

template < typename TArg0 >
{
public:
typedef void (*function_t)(TArg0);
: m_func(func)
{
m_arg0 = new TThunkArg(this, arg0);
{
delete m_arg0;
throw new std::runtime_error("Could not create a thread");
}
}

void join()
{
}

private:
struct TThunkArg
{
TArg0 Arg0;
: Self(self)
, Arg0(arg0)
{}
};
{
TThunkArg *args = reinterpret_cast<TThunkArg*>(unsafe_args);
try
{
args->Self->m_func(args->Arg0);
}
catch(...)
{
delete args;
throw;
}

delete args;
return 0;
}
function_t m_func;
TThunkArg *m_arg0;
};

• Aside: can you use boost? They provided a threading library before it got in the standard. – user14393 Apr 25 '15 at 6:35
• No Boost for this codebase. – Cat Zimmermann Apr 25 '15 at 7:39

You can put the unsafe_args in a auto_ptr so RAII can delete them safely. This is safe because you will not be copying it around.

static PORTABLE_THREAD_FUNC_DECL thunk(void *unsafe_args)
{
std::auto_ptr<TThunkArg> args(reinterpret_cast<TThunkArg*>(unsafe_args));
args->Self->m_func(args->Arg0);

return 0;
}


Also don't worry about having to new the args; you are creating a new thread, this is much more expensive than a quick malloc call.

• I don't see a reason not to make portable_thread_create and portable_thread_join static members of thread. If they are not meant for use outside the class, also make them private.

• _beginthreadex, pthread_create and CreateThread all expect a pointer to a C function. Technically, a C function is not the same as a static class member. Most sane compilers will treat them the same way, but for optimal portability, you should define you thunk function as a global extern "C":

extern "C" PORTABLE_THREAD_FUNC_DECL thunk(void *unsafe_args) { /* ... */ }

• std::auto_ptr, even though deficient if compared to its C++11 replacements, is still cleaner and safer than raw new/delete in most scenarios.

• thread currently has no destructor, so it is not cleaning up the platform specific thread handle. I think you have a resource leak there. Also, it does not join or detach the thread on destruction. Even though this is how the standard C++ thread behaves, I would advise that you perform a default action in the destructor instead of leaving room for undefined behavior.

• about point 2: or add extern "C" to the PORTABLE_THREAD_FUNC_DECL macro – ratchet freak Apr 25 '15 at 4:10
• The portable_thread functions are C functions from elsewhere. Most of the C code is elided, but it's safe to say PORTABLE_THREAD_FUNC_DECL contains the extern "C" and other calling conventions for other platforms. portable_thread_detach is definitely needed, but I think join in a destructor might be confusing. – Cat Zimmermann Apr 25 '15 at 4:44