一种破坏"线程"类的方法

dim*_*mba 3 c++ multithreading

这是我的线程类的骨架:

class MyThread {
public:
   virutal ~MyThread();

   // will start thread with svc() as thread entry point
   void start() = 0;        

   // derive class will specialize what the thread should do
   virtual void svc() = 0;                
};
Run Code Online (Sandbox Code Playgroud)

在代码的某处我创建了一个实例,MyThread后来我想要销毁它.在这种情况下MyThread~MyThread()被称为.MyThread:svc()仍在运行并使用对象的数据成员.因此MyThread:svc(),在继续使用析构函数之前,我需要礼貌地告知停止旋转.

破坏线程对象的可接受方法是什么?

注意:我正在寻找平台无关的解决方案.

UPD:很明显问题的根源在于C++对象代表线程和OS线程之间没有关系.所以问题是:在对象去除的上下文中,是否有一种可接受的方法可以使线程对象像普通的C++对象一样运行,或者它应该被视为一个不寻常的对象(例如,我们应该在调用它之前调用join()吗?

pet*_*hen 7

考虑到您的附加要求发布为对Checkers的回复的评论(这是最直接的方式):

我同意由于各种原因加入DTor是有问题的.但是从那开始,线程对象的生命周期与OS线程对象的生命周期无关.


首先,您需要将线程使用的数据与线程对象本身分开.它们是具有不同生命期要求的不同实体.

一种方法是重新安装数据,并且任何想要访问它的线程都拥有对数据的强引用.这样,任何线程都不会突然陷入虚空,但是一旦没有人接触到数据,数据就会被破坏.


第二,关于线程加入时被破坏的线程对象:
我不确定这是不是一个好主意.线程对象通常是一种查询线程状态的方法 - 但是一旦线程完成,线程对象就会死掉,没有人可以告诉你线程完成了.

通常,我完全将线程对象的生命周期与OS线程的生命周期分离:销毁线程对象不应该影响线程本身.我看到两种基本方法:

  1. 线程句柄对象 - 由线程创建者返回的引用再次计数,可以在不影响OS线程的情况下尽早释放.它会暴露诸如Join,, 等方法IsFinished,并且可以提供对线程共享数据的访问.

(如果线程对象持有相关的执行状态,则threafFunc本身可以保存对它的引用,从而确保在线程结束之前不会释放实例)

  1. Thin Wrapper - 您只需在OS线程句柄周围创建一个临时文件.您无法轻松保持线程的其他状态,但它可能足以使其工作:在任何地方,您都可以将OS线程句柄转换为线程对象.大多数通信 - 例如告诉线程终止 - 将通过共享数据.

对于您的代码示例,这意味着:将其start() 与.分开svc()

你大致使用这个API(XxxxPtr可以是例如boost :: shared_ptr):

class Thread
{
   public:
     bool IsFinished();
     void Join();
     bool TryJoin(long timeout); 

     WorkerPtr GetWorker();

     static ThreadPtr Start(WorkerPtr worker); // creates the thread
};


class Worker
{
private:
   virtual void Svc() = 0;

   friend class Thread; // so thread can run Svc()
}
Run Code Online (Sandbox Code Playgroud)

Worker可以包含一个ThreadPtr本身,保证线程对象在执行期间存在Svc().如果允许多个线程处理相同的数据,则必须是一个线程列表.否则,Thread::Start必须拒绝已经与线程关联的Worker.


动机:如何处理阻塞的流氓线程?
假设一个线程因某种原因未能在一段时间内终止,即使你告诉它.你只有三个选择:

  • 死锁,你的应用程序挂起.如果您加入析构函数,通常会发生这种情况.
  • 暴力终止线程.这可能是应用程序的暴力终止.
  • 让线程在其自己的数据上运行完成 - 您可以通知用户,谁可以安全地保存并退出.或者你只是让流氓线程在它自己的数据副本上跳舞(不再由主线程引用)直到它完成.