首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >创建阻塞队列

创建阻塞队列
EN

Stack Overflow用户
提问于 2014-05-15 01:55:29
回答 2查看 11K关注 0票数 2

有时,BlockingQueue的这种实现和执行只会起作用。有时它会出现分段错误。知道为什么吗?

代码语言:javascript
复制
#include <thread>
using std::thread;
#include <mutex>
using std::mutex;
#include <iostream>
using std::cout;
using std::endl;
#include <queue>
using std::queue;
#include <string>
using std::string;
using std::to_string;
#include <functional>
using std::ref;

template <typename T>
class BlockingQueue {
private:
    mutex mutex_;
    queue<T> queue_;
public:
    T pop() {
        this->mutex_.lock();
        T value = this->queue_.front();
        this->queue_.pop();
        this->mutex_.unlock();
        return value;
    }

    void push(T value) {
        this->mutex_.lock();
        this->queue_.push(value);
        this->mutex_.unlock();
    }

    bool empty() {
        this->mutex_.lock();
        bool check = this->queue_.empty();
        this->mutex_.unlock();
        return check;
    }
};

void fillWorkQueue(BlockingQueue<string>& workQueue) {
    int size = 40000;
    for(int i = 0; i < size; i++)
        workQueue.push(to_string(i));
}

void doWork(BlockingQueue<string>& workQueue) {
    while(!workQueue.empty()) {
        workQueue.pop();
    }   
}

void multiThreaded() {
    BlockingQueue<string> workQueue;
    fillWorkQueue(workQueue);
    thread t1(doWork, ref(workQueue));
    thread t2(doWork, ref(workQueue));
    t1.join();
    t2.join();
    cout << "done\n";
}

int main() {
    cout << endl;

    // Multi Threaded
    cout << "multiThreaded\n";
    multiThreaded();
    cout << endl;
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-05-15 02:03:32

请看这里:

What do I get from front() of empty std container?

如果你在一个空的容器上调用.front(),就会发生不好的事情,最好先检查.empty()

尝试:

代码语言:javascript
复制
T pop() {
    this->mutex_.lock();
    T value;
    if( !this->queue_.empty() )
    {
        value = this->queue_.front();  // undefined behavior if queue_ is empty
                                       // may segfault, may throw, etc.
        this->queue_.pop();
    }
    this->mutex_.unlock();
    return value;
}

注意:由于原子操作在这类队列中很重要,因此我建议对API进行更改:

代码语言:javascript
复制
bool pop(T &t);  // returns false if there was nothing to read.

更好的是,如果你真的在重要的地方使用它,你可能想要在删除之前标记正在使用的项目,以防失败。

代码语言:javascript
复制
bool peekAndMark(T &t);  // allows one "marked" item per thread
void deleteMarked();     // if an item is marked correctly, pops it.
void unmark();           // abandons the mark. (rollback)
票数 4
EN

Stack Overflow用户

发布于 2014-05-15 02:00:09

问题应该在这里:

代码语言:javascript
复制
while(!itemQueue.empty()) {
    itemQueue.pop();
}

在检查一个值的时候保留互斥锁,然后释放互斥锁,可能会发生另一个线程被执行的情况,发现有一个值被留下并弹出它。在最坏的情况下,没有留下任何项目,并且第一个线程试图在没有留下任何元素的情况下弹出。

解决方案是在与在同一锁定部分中检查是否为空的同一部分中的内部队列上进行front/pop调用,然后行为将始终被定义。

另一个建议是在使用互斥锁时使用std::lock_guard,因为它提高了可读性,并确保无论发生什么情况都会释放互斥锁。

考虑到这两个建议,您的pop方法可能如下所示:

代码语言:javascript
复制
T pop() {
    std::lock_guard lock(this->mutex_); //mutex_ is locked
    T value;
    if( !this->queue_.empty() )
    {
        value = this->queue_.front();
        this->queue_.pop();
    }
    return value;
} //mutex_ is freed
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23661759

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档