在C ++中将互斥锁定在析构函数中11 [英] Locking a mutex in a destructor in C++11

查看:174
本文介绍了在C ++中将互斥锁定在析构函数中11的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些代码需要线程安全和异常安全。下面的代码是我的问题的非常简化版本:

I have some code which need to be thread safe and exception safe. The code below is a very simplified version of my problem :

#include <mutex>
#include <thread>

std::mutex mutex;
int n=0;

class Counter{
public:
    Counter(){
        std::lock_guard<std::mutex>guard(mutex);
        n++;}
    ~Counter(){
        std::lock_guard<std::mutex>guard(mutex);//How can I protect here the underlying code to mutex.lock() ?
        n--;}
};

void doSomething(){
    Counter counter;
    //Here I could do something meaningful
}

int numberOfThreadInDoSomething(){
    std::lock_guard<std::mutex>guard(mutex);
    return n;}



我有一个互斥量,我需要锁定析构函数一个东西。问题是我的析构函数不应该抛出异常。

I have a mutex that I need to lock in the destructor of an object. The problem is that my destructor should not throw exceptions.

我能做什么?

0)用一个原子变量替换 n (当然它会做这里的诀窍,但这不是我的问题的要点)

0) I cannot replace n with an atomic variable (of course it would do the trick here but that is not the point of my question)

1)我可以用自旋锁替换我的互斥锁

1) I could replace my mutex with a spin lock

2)我可以尝试锁定到一个无限循环,直到我最终获得锁没有异常引发

2) I could try and catch the locking into an infinite loop until I eventualy acquire the lock with no exception raised

这些解决方案都不是很有吸引力。你有同样的问题吗?

None of those solution seems very appealing. Did you have the same problem ? How did you solve it ?

推荐答案

正如Adam H. Peterson建议的,我终于决定写一个不抛弃的互斥体: / p>

As suggested by Adam H. Peterson, I finally decided to write a no throw mutex :

class NoThrowMutex{
private:
    std::mutex mutex;
    std::atomic_flag flag;
    bool both;
public:
    NoThrowMutex();
    ~NoThrowMutex();
    void lock();
    void unlock();
};

NoThrowMutex::NoThrowMutex():mutex(),flag(),both(false){
    flag.clear(std::memory_order_release);}

NoThrowMutex::~NoThrowMutex(){}

void NoThrowMutex::lock(){
    try{
        mutex.lock();
        while(flag.test_and_set(std::memory_order_acquire));
        both=true;}
    catch(...){
        while(flag.test_and_set(std::memory_order_acquire));
        both=false;}}

void NoThrowMutex::unlock(){
    if(both){mutex.unlock();}
    flag.clear(std::memory_order_release);}

想法是有两个互斥,而不是只有一个。真正的互斥是使用 std :: atomic_flag 实现的自旋互斥。这个自旋互斥被一个 std :: mutex 保护,可能会抛出。

The idea is to have two mutex instead of only one. The real mutex is the spin mutex implemented with an std::atomic_flag. This spin mutex is protected by a std::mutex which could throw.

获取互斥体,并且以仅一个原子操作的成本设置标志。如果标准互斥体不能被立即锁定,则线程将进入休眠状态。

In a normal situation, the standard mutex is acquired and the flag is set with a cost of only one atomic operation. If the standard mutex cannot be locked immediately, the thread is going to sleep.

如果由于任何原因标准互斥体抛出,互斥体将进入其自旋模式。发生异常的线程将循环,直到它可以设置标志。因为没有其他线程意识到这个线程完全抛弃了标准互斥,他们也可以旋转。

If for any reason the standard mutex throws, the mutex will enter its spin mode. The thread where the exception occured will then loop until it can set the flag. As no other thread is aware that this thread bybassed completely the standard mutex, they could spin too.

在最坏的情况下,这种锁定机制降级为自旋锁。大多数时候它的反应就像一个正常的互斥。

In the worst case scenario, this locking mechanism degrades to a spin lock. Most of the time it reacts just like a normal mutex.

这篇关于在C ++中将互斥锁定在析构函数中11的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆