STL和多线程

Goo*_*ofy 3 c++ stl

我知道,当我在多个线程内的单个STL容器上执行操作时,我需要使用互斥锁.但是,我想知道此规则是否有任何例外.请考虑我正在尝试实施的简化方案.

我有多个线程向容器添加元素,操作包含互斥锁定/解锁.然后线程以某种方式通知(例如在linux上使用eventfd)单线程专用于调度此容器中的元素.我想要做的是访问容器中的第一个元素而不使用互斥锁.示例代码基于deque,但请注意我可以使用任何具有队列功能的容器:

std::mutex     locker;
std:deque<int> int_queue;
int            fd; // eventfd
eventfd_t      buffer;
bool           some_condition;
Run Code Online (Sandbox Code Playgroud)

线程1,2,3等

locker.lock ();
int_queue.push_back (1);
locker.unlock ();

eventfd_write (fd, 1);
Run Code Online (Sandbox Code Playgroud)

专用于调度元素的线程:

while (true)
{
    bool some_condition (true);

    locker.lock ();
    if (int_quque.empty () == false)
    {
        locker.unlock ();
    }
    else
    {
        locker.unlock ();
        eventfd_read (fd, &buffer);
    }

    while (some_condition)
    {
        int& data (int_queue.front ());

        some_condition = some_operation (data); // [1]
    }

    locker.lock ();
    int_queue.pop ();
    locker.unlock ();
}
Run Code Online (Sandbox Code Playgroud)

[1]我会多次对signle元素执行some_operation(),这就是为什么我想在这里避免互斥锁定.这很贵.

我想知道这段代码是否会导致任何同步问题.

How*_*ant 6

你需要的是参考稳定性.也就是说,当容器是push_back'd时,如果第一个元素的引用没有失效,那么你可以这样使用容器.即便如此,您还是希望获得锁定前面元素的引用.

std::condition_variable对事件通知比较熟悉,所以我会用它:

#include <mutex>
#include <condition_variable>
#include <deque>

std::mutex              locker;
std::deque<int>         int_queue;
std::condition_variable cv;

void thread_1_2_3()
{
    // use lock_guard instead of explicit lock/unlock
    //    for exception safety
    std::lock_guard<std::mutex> lk(locker);
    int_queue_.push_back(1);
    cv.notify_one();
}

void dispatch()
{
    while (true)
    {
        bool some_condition = true;
        std::unique_lock<std::mutex> lk(locker);
        while (int_queue.empty())
            cv.wait(lk);
        // get reference to front under lock
        int& data = int_queue.front();
        lk.unlock();
        // now use the reference without worry
        while (some_condition)
            some_condition = some_operation(data);
        lk.lock();
        int_queue.pop_front();
    }
}
Run Code Online (Sandbox Code Playgroud)

23.3.3.4 [deque.modifiers]说这个push_back:

在deque两端的插入使deque的所有迭代器无效,但对deque元素的引用的有效性没有影响.

这是允许您在锁外部挂起该引用的关键.如果thread_1_2_3 在中间开始插入或删除,则您不能再挂起此引用.

你不能这样使用vector.但你可以用list这种方式.检查要使用此方式的每个容器以获得参考稳定性.