【问题标题】:Is this interface thread-safe?这个接口是线程安全的吗?
【发布时间】:2015-08-23 11:27:06
【问题描述】:

我想做一个控制循环界面。

它有should_stop() 方法来检查循环是否应该中断或继续。

它确实会监听SIGINT 信号(Ctrl+C)并且在它得到信号后should_stop() 方法返回True。

现在看来这个界面可以工作了。

但我不确定这个接口是线程安全的。

LoopInterface.h 文件

#include "signal.h"
#include "pthread.h"

#define LOCK(mutex)     pthread_mutex_lock(&mutex)
#define UNLOCK(mutex)   pthread_mutex_unlock(&mutex)

class LoopInterface {
public:
    LoopInterface(){
        LOCK(_lock_is_signal_registered);
        bool temp = _is_signal_registered;
        UNLOCK(_lock_is_signal_registered);
        if(!temp)
        {
            register_signal();
        }
    }

    bool should_stop()
    {
        LOCK(_lock_should_stop);
        bool temp = _should_stop;
        UNLOCK(_lock_should_stop);
        return _should_stop;
    }

private:

    static void register_signal()
    {
        LOCK(_lock_is_signal_registered);
        _is_signal_registered = true;
        UNLOCK(_lock_is_signal_registered);

        signal(SIGINT, &LoopInterface::signal_handler);
    }

    static void signal_handler(int sig){
        LOCK(_lock_should_stop);
        _should_stop = true;
        UNLOCK(_lock_should_stop);
    }

    static bool _should_stop;
    static bool _is_signal_registered;
    static pthread_mutex_t _lock_should_stop, _lock_is_signal_registered;
};

LoopInterface.cpp 文件

#include "LoopInterface.h"
bool LoopInterface::_should_stop = false;
bool LoopInterface::_is_signal_registered = false;
pthread_mutex_t LoopInterface::_lock_should_stop;
pthread_mutex_t LoopInterface::_lock_is_signal_registered;

这就是它的使用方式。

/************Threads*************/
#include "LoopInterface.h"
class A : public LoopInterface{

};

void threadX(){
    A a;
    while(!a.should_stop()){
        //do something...
    }
}

你能告诉我这个接口可以线程安全地工作吗?还是不行?

如果不是,问题是什么?


其他问题

我的同步代码还有一个问题。

由于在signal_handler 中调用pthread_mutex_lockshould_stop 方法正在锁定相同的mutex,因此经常发生死锁。

我发现了一个article 声明不应在信号处理程序中调用与线程相关的函数。

我想我应该找到另一种方法来同步我的成员变量。

【问题讨论】:

    标签: c++ multithreading thread-safety


    【解决方案1】:

    显然,这段代码不是线程安全的:变量_should_stop 由某个不受控制的线程中的信号设置,并在运行自己的线程的LoopInterface 中读取。根本没有同步。这种方法只有在只有一个线程时才能是线程安全的。

    您可以使用

    使代码线程安全(相对于这个特定的变量)
    static std::atomic<bool> _should_stop;
    

    由于此时您对任何其他值不感兴趣,因此您可以读取带有std::memory_order_relaxed 标志的变量。

    如果LoopInterface的构造函数是从多个线程调用的,当然还需要同步访问_is_signal_registered

    【讨论】:

    • 谢谢。但是atomic 类似乎生活在 c++11 中,这对我来说是不可用的。我会尝试用mutex同步两个变量。
    • 亲爱的@Dietmar。我在代码中添加了同步。但是我不知道如何在这里同步初始化两个互斥对象。
    • @JeaJunLEE:由于您使用 pthread,您可以简单地使用 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 来静态初始化互斥锁。
    • 首先,嗨 @DietmarKühl ))) 其次,JaeJunLEE,即使 C++ 原子不适合您,您仍然可以使用互斥锁以外的其他东西。如果您只在 Intel 上运行您的代码,您可以使您的变量 volatile 并享受 Intel 提供的严格的内存排序。我不是在提倡这个,只是让你知道。或者您可以使用操作系统提供的(或编译器提供的)原子函数。应该有的。
    • 亲爱的@DietmarKühl,我发现同步成员变量的一个问题。它看起来像线程安全代码,但很可能会产生死锁问题。请查看我编辑的问题。
    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多