patterncppMinor
Portable C++98 thread class akin to std::thread
Viewed 0 times
stdthreadportableclassakin
Problem
I want a homegrown version of C++11's
Two notes:
```
/ 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;
}
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
Also don't worry about having to
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.