简体   繁体   English

对条件变量使用多个互斥锁

[英]Using more than one mutex with a conditional variable

Is there a mechanism to have a conditional variable use multiple mutexes?是否有一种机制可以让条件变量使用多个互斥锁? I am in Linux and pthreads in C++.我在 Linux 和 pthreads 在 C++。

In an application, I need two mutexes (instead of one) to be atomically acquired and released by pthread_cond_wait(), but the function only accepts one.在一个应用程序中,我需要两个互斥锁(而不是一个)由 pthread_cond_wait() 以原子方式获取和释放,但 function 只接受一个。

I have a class named BlockingManager and it has the method:我有一个名为 BlockingManager 的 class ,它具有以下方法:

blockMeFor( pthread_cond_t* my_cond, pthread_mutex_t* my_lock, set<int> waitees);

and I am using it, assuming that it acquires/releases the mutex just like pthread_cond_wait.我正在使用它,假设它像 pthread_cond_wait 一样获取/释放互斥锁。

The problem is that for implementing blockingManager I need an internal mutex too and both of these mutexes should be acquired and released atomically.问题是,为了实现blockingManager,我也需要一个内部互斥锁,这两个互斥锁都应该被原子地获取和释放。

There is a somehow related discussion here, it says waiting for more than one mutex yields undefined behavior.这里有一个相关的讨论,它说等待多个互斥体会产生未定义的行为。 http://sourceware.org/ml/libc-help/2011-04/msg00011.html http://sourceware.org/ml/libc-help/2011-04/msg00011.html

A producer/consumer model for the problem I am facing follows:我面临的问题的生产者/消费者 model 如下:

We have multiple clients.我们有多个客户。 Each client has some tasks.每个客户都有一些任务。 Each task probably has multiple prerequisites (either among the tasks of the same client or other clients).每个任务可能有多个先决条件(在同一客户端或其他客户端的任务中)。 Each client has one consumer thread.每个客户端都有一个消费者线程。 The tasks are assigned to the clients from one producer thread.任务从一个生产者线程分配给客户端。 The newly assigned task may be eligible to be done before the previous tasks.新分配的任务可能有资格在之前的任务之前完成。 There may be no task to be done at some moments, but if there is a task to be done, at least one should be done.在某些时候可能没有任务要完成,但如果有任务要完成,至少应该完成一个。 (It should be work-conserving) (应该是工作守恒)

I am using one condvar per consumer thread and it would block once there is no task to be done for that thread.我为每个消费者线程使用一个 condvar,一旦该线程没有任务要完成,它就会阻塞。 The condvar may be signaled by either condvar 可以通过以下任一方式发出信号

  • The producer thread assigning a new task.分配新任务的生产者线程。

  • Another consumer thread finishing a task.另一个消费者线程正在完成一项任务。

I am using one mutex per consumer to protect the shared data-structures between producer & consumer.我为每个消费者使用一个互斥锁来保护生产者和消费者之间的共享数据结构。 And one mutex (internal mutex) to protect the shared data-structures between multiple-consumers.还有一个互斥锁(内部互斥锁)来保护多个消费者之间的共享数据结构。

In C++11 (if your compiler supports it) you can use std::lock to lock two mutexes at once (without deadlock).在 C++11 (如果您的编译器支持它)中,您可以使用std::lock一次锁定两个互斥锁(没有死锁)。 You can use this to build a Lock2 class which references two mutexes.您可以使用它来构建引用两个互斥锁的Lock2 class。 And then you can use std::condition_variable_any to wait on a Lock2 .然后您可以使用std::condition_variable_any等待Lock2 This all might look something like:这一切可能看起来像:

#include <mutex>
#include <condition_variable>

std::mutex m1;
std::mutex m2;
std::condition_variable_any cv;

class Lock2
{
    std::mutex& m1_;
    std::mutex& m2_;

public:
    Lock2(std::mutex& m1, std::mutex& m2)
        : m1_(m1), m2_(m2)
    {
        lock();
    }

    ~Lock2() {unlock();}

    Lock2(const Lock2&) = delete;
    Lock2& operator=(const Lock2&) = delete;

    void lock() {std::lock(m1_, m2_);}
    void unlock() {m1_.unlock(); m2_.unlock();}
};

bool not_ready() {return false;}

void test()
{
    Lock2 lk(m1, m2);
    // m1 and m2 locked
    while (not_ready())
        cv.wait(lk);  // m1 and m2 unlocked
    // m1 and m2 locked
}  // m1 and m2 unlocked

If your compiler does not yet support these tools, you can find them in boost.如果你的编译器还不支持这些工具,你可以在 boost.js 中找到它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM