c++ - C++ 队列中的 pop 和访问是线程安全的

标签 c++ multithreading queue thread-safety

我知道 std::queue 不是线程安全的,但我不想锁定队列。 所以我对使用情况使用弹出和推送限制。

例如, 当我想弹出时: 我有一个枚举来表示第一个元素状态

enum {
    Busy = 1,
    Unused,
}

当我将元素添加到队列时:

void UserAdd() {
    lock.lock();
    element.status = BUSY;
    queue.push_back(element);
    lock.unlock();
}

当我访问时:

//only visit function, and every element only called once.
void UserVisit() {
    auto header = queue.front();
    .......
    queue.front().status = UNUSED;
    return ;
}

当我想要弹出元素时,我判断第一个元素的状态。

如果第一个元素为 Busy,则等待;

如果第一个元素未使用,则弹出;

void UserPop() {
    while (queue.front().status != Unused) {
        usleep(200);
    }
    lock.lock();
    queue.pop();
    lock.unlock();
}

线程A:1.UserAdd,2.UserVisit,1.UserAdd,2.UserVisit循环...

线程B:1.UserPop。

UserPop() && UserVisit 线程安全吗?

我认为它是线程安全的。

最佳答案

 没有线程安全

请注意,成员函数 pop() 确实会修改队列。如果 UserPop() 被多个线程同时调用,则一个线程可以通过调用 pop() 来修改队列,同时另一个线程通过调用来读取队列front():

void UserPop() {
    while (queue.front().status != Unused) { // <-- read queue
        usleep(200);
    }
    queue.pop(); // <-- modify queue
}

由于队列本身 std::queue 不为您处理并发访问,因此 UserPop() 不是线程安全的。

<小时/>

使其线程安全

使其成为线程安全的一个简单方法是添加互斥体并在读取或修改队列时对其持有锁:

std::mutex mtx;

// ...

void UserPop() {
    std::unique_lock<std::mutex> lck(mtx);
    // mtx is locked at this point
    while (queue.front().status != Unused) {
        lck.unlock();
        usleep(200); // mtx is not locked
        lck.lock();
    }
    // mtx is locked at this point
    queue.pop();
}
上面的

std::queue 的成员函数 front()pop() 总是在持有互斥锁时被调用.

但是,您可能需要考虑使用 std::condition_variable反而。它提供了对繁忙等待的优化:

std::mutex mtx;
std::condition_variable cv;

void UserPop() {
    std::unique_lock<std::mutex> lck(mtx);
    cv.wait(lck, [this]() { return queue.front().status == Unused; });
    queue.pop();
}

关于c++ - C++ 队列中的 pop 和访问是线程安全的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60262705/

相关文章:

c++ - 关于内存泄漏的问题

c++ - 为什么 'CreateEvent' 创建的 HANDLE 在另一个进程中无效?

java - Java中如何让线程等待1ms?

queue - 替换 jms 队列中的消息

Java(字符串)——它有什么作用?

c++ - WriteProcessMemory 和类似函数是否会使可能缓存的数据无效?

c++ - 尝试在头文件中私有(private)声明 vector 时出错

java - 简单的守护线程不输出消息

c# - 跟踪 c#/.NET 任务流

java - ORA-01031 : insufficient privileges creating JMS connection to Oracle topic