HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Portable C++98 thread class akin to std::thread

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
stdthreadportableclassakin

Problem

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:

  • 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.



  • 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 /
int portable_thread_create(portable_thread_t *)
{
pthread_create() OR
_beginthreadex()
}

#define PORTABLE_THREAD_FUNC_DECL void *
#define PORTABLE_THREAD_FUNC_DECL unsigned int __cdecl OR

void portable_thread_join(portable_thread_t)
{
pthread_join() OR
WaitForSingleObject()
}

template
class thread
{
public:
typedef void (*function_t)(TArg0);
thread(function_t func, TArg0 arg0)
: m_func(func)
{
m_arg0 = new TThunkArg(this, arg0);
if (0 != portable_thread_create(&m_thread, thunk, m_arg0))
{
delete m_arg0;
throw new std::runtime_error("Could not create a thread");
}
}

void join()
{
portable_thread_join(m_thread);
}

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

Solution

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 args(reinterpret_cast(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.

Code Snippets

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;
}

Context

StackExchange Code Review Q#87903, answer score: 4

Revisions (0)

No revisions yet.