使用 boost 线程:发出信号并等待终止

Posted

技术标签:

【中文标题】使用 boost 线程:发出信号并等待终止【英文标题】:Using a boost thread: Signal and wait for termination 【发布时间】:2014-08-01 14:32:07 【问题描述】:

我目前正在编写一个 c/c++ dll 以供以后主要在 Delphi 中使用,而且我对 Delphi 中的线程比 c/c++ 更熟悉,尤其是 boost。所以我想知道如何实现以下场景?

class CMyClass

    private:
        boost::thread* doStuffThread;
    protected:
        void doStuffExecute(void)
        
            while(!isTerminationSignal()) // loop until termination signal
            
                // do stuff
            

            setTerminated(); // thread is finished
        ;
    public:
        CMyClass(void)
        
            // create thread
            this->doStuffThread = new boost::thread(boost::bind(&CMyClass::doStuffExecute, this));
        ;

        ~CMyClass(void)
        
            // finish the thread
            signalThreadTermination();
            waitForThreadFinish();

            delete this->doStuffThread;

            // do other cleanup
        ;

我有无数关于增强线程、信号和互斥锁的文章,但我不明白,可能是因为现在是星期五;)还是我认为这样做不可行?

问候 丹尼尔

【问题讨论】:

我会声明“volatile bool needStop”变量,并使用 thread::join 来等待您将 needStop 设置为 true 后实际停止的线程。 @VadimKalinsky,不不不! - volatile 不适用于多线程。使用std::atomic<bool> 【参考方案1】:

只需使用原子布尔值来告诉线程停止:

class CMyClass

private:
    boost::thread doStuffThread;
    boost::atomic<bool> stop;
protected:
    void doStuffExecute()
    
        while(!stop) // loop until termination signal
        
            // do stuff
        

        // thread is finished
    ;
public:
    CMyClass() : stop(false)
    
        // create thread
        doStuffThread = boost::thread(&CMyClass::doStuffExecute, this);
    ;

    ~CMyClass()
    
        // finish the thread
        stop = true;
        doStuffThread.join();

        // do other cleanup
    ;

要等待线程完成,您只需加入它,这将阻塞,直到它完成并可以加入。无论如何你都需要加入线程才能销毁它,否则它会终止你的程序。

不需要使用指针和new创建线程,直接使用boost::thread对象即可。在堆上创建所有内容是浪费、不安全和糟糕的风格。

无需使用boost::bind 将参数传递给thread 构造函数。多年来boost::thread 一直支持将多个参数直接传递给其构造函数,并在内部进行绑定。

在创建新线程之前stop 已经初始化为false 很重要,否则如果新线程很快产生,它可能会在初始化之前检查stop 的值,并且可能会发生从未初始化的内存中读取一个true的值,然后它就永远不会进入循环。

在风格方面,写foo(void) 被许多 C++ 程序员认为是令人厌恶的可憎之物。如果你想说你的函数不带参数,那就写foo()

【讨论】:

未定义的行为的哪一部分与您无关?如果没有原子,编译器可以将循环转换为:if (!stop) while (true) /* do work */ ,因为它知道正在读取的非原子、非易失性变量不能更改,除非在具有未定义行为的程序中,因此它可以假设它永远不会更改跨度> 查看我之前的评论,或阅读Benign data races: what could possibly go wrong?。仅仅因为您不了解问题并不意味着它不是真实的。 How to miscompile programs with “benign” data races 中的第 2.3 节正是这种情况。这两个链接是由一些世界***的数据竞赛和多线程专家编写的,但是,嘿,也许他们只是偏执,你是对的。 volatile 对于 C++ 中的线程间通信既非必要也不充分。 drdobbs.com/parallel/volatile-vs-volatile/212701484 @BrandonKohn 多线程之于单线程,就像相对论之于经典力学一样。 您对同时性和事件顺序的直觉不会延续。此外,您引用的关于竞争条件的问答不是 C++ 特定的。对于 C++,标准有一个非常精确的声明,这是这里唯一相关的引用。

以上是关于使用 boost 线程:发出信号并等待终止的主要内容,如果未能解决你的问题,请参考以下文章

线程取消(pthread_cancel)

线程取消(pthread_cancel)

AutoResetEvent类的使用

线程取消(pthread_cancel)

线程取消(pthread_cancel)

线程取消(pthread_cancel)