2012-07-16 48 views
0

我正在做一个围绕win32线程和pthreads的包装类,类似于C++ 11线程api的风格。 我的问题是关于在实际线程退出时更新线程对象实例。以下是我的解决方案,但我不确定它是否安全。线程包装器实现问题

/* Thread wrapper class */ 
    class Thread 
    { 
    public: 
     enum ThreadState 
     { 
      DETACHED = 0, 
      RUNNING 
     }; 

     Thread(); 
     Thread(void* (*start) (void*), void* arg); 
     ~Thread(); 

     Thread& operator=(Thread& other); 
     void Join(); 
     int32_t SetPriority(int32_t priority); 
     void Detach(); 
     ThreadHandle GetNativeHandle(); 
     ThreadState GetThreadState(); 

    private: 
     ThreadHandle mHandle; 
     ThreadState mState; 
     void* (*mFunctionPointer) (void*); 
     void* mArg; 

     static void* Run(void* arg); 
     ThreadHandle _CreateThread(void* (*start) (void*), void* arg); 
     void _JoinThread(ThreadHandle& handle); 

    }; 

第二个构造函数启动一个线程。下面是执行:

Thread::Thread(void* (*start) (void*), void* arg) 
    { 
     mFunctionPointer = start; 
     mArg = arg; 
     mState = Thread::RUNNING; 

     mHandle = _CreateThread(&Run, (void*)this); 
     if (!mHandle) 
      mState = Thread::DETACHED; 
    } 

它创建一个运行运行方式,沿着一个指向这个对象实例通过一个线程。原因是一旦线程执行了它将状态设置为DETACHED以表示完成的功能。

这里是运行方法

void* Thread::Run(void* arg) 
    { 
     Thread* thread = static_cast<Thread*>(arg); 

     if (thread && thread->mFunctionPointer && thread->mArg && thread->mState == Thread::RUNNING) 
      thread->mFunctionPointer(thread->mArg); 

     if (thread && thread->mFunctionPointer && thread->mArg && thread->mState == Thread::RUNNING) 
      thread->Detach(); 

     return NULL; 
    } 

而且这是分离(),它也被称为上线的析构函数:

void Thread::Detach() 
    { 
     mState = Thread::DETACHED; 
     mHandle = NULL; 
     mArg = NULL; 
     mFunctionPointer = NULL; 
    } 

我喜欢这种感觉是不是安全的。例如,如果线程对象在堆栈上构建并在其线程运行时超出范围。 Thread对象析构函数将其状态和数据成员设为NULL,但内存位置可能会被覆盖否?

有没有解决这个问题的好办法?

感谢

+1

FYI,Boost.Thread(http://www.boost.org/doc/libs/release/doc/html/thread.html)是周围的win32的包装和并行线程。在最新版本的Boost(1.50)中,进行了更改,以便API与C++ 11的“std :: thead”相匹配。 – 2012-07-16 16:48:48

+1

我快速搜索了几个C++ 11 std :: thread页面。两者都以使用Thread-> join()的例子开始。这就像Deja vu重新:创建/终止/加入广告的恶心。 Delphi,Java,C#和现在的C++ 11 - 同样的旧垃圾。标准委员会的成员是否曾经写过任何不平凡的多线程软件?为什么开发人员赶上join()?什么教科书/网页作者负责?生活时间的应用程序线程和线程池,很好,所以我们得到什么:'join()'无论如何,祝你好运 - 你将需要它:) – 2012-07-16 18:00:59

回答

1

你注定,如果线程实例超出范围,而不线程之前被连接。使Run()成为一个自由或静态函数并复制所有数据,该函数需要运行到动态分配的内存中并让Run()释放该内存。

在Run()中没有必要进行太多的测试。由于您的c'tor参数已经与CreateThread()兼容,只需将函数和参数传递给CreateThread即可,您应该没问题。

亲切的问候

的Torsten

+0

如果对象会执行Join()(如果活动线程)在析构函数,那么它会被认为是安全的吗? – KaiserJohaan 2012-07-16 16:10:30

+0

@KaiserJohaan当然,线程,调用d'或将阻塞,直到Run()函数完成。但是你通常不想让代码加入该线程,因为你可能希望有多个Thread对象指向同一个真正的执行线程。如果您的Thread类不可复制,则无法将Thread对象存储在容器中。 – 2012-07-16 16:47:24

+0

@TorstenRobitzki'可能想要多个Thread对象指向同一个真正的执行线程' - 我保留永不这样做的权利:)同样在堆栈上构建线程对象。同样使用任何不是指针类型的容器,因此需要任何种类的“真实”拷贝来加载它。 'myContainer '不好,'myContainer <*Thread>不错:)。我不明白为什么有人会尝试在另一个线程堆栈上创建一个线程对象 - 这是将RAII转换为多线程的一种尝试,因为除了这样做之外,我什么也看不到。 – 2012-07-16 17:43:16