创建阻塞队列

Chr*_*ord 2 c++ multithreading blockingqueue c++11

有时,这种实施和执行BlockingQueue确实有效。有时会出现段错误。知道为什么吗?

#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;
}
Run Code Online (Sandbox Code Playgroud)

小智 5

看这里:

我可以从空 std 容器的 front() 得到什么?

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

尝试:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

bool pop(T &t);  // returns false if there was nothing to read.
Run Code Online (Sandbox Code Playgroud)

更好的是,如果您实际上在重要的地方使用它,您可能希望在删除之前标记正在使用的项目,以防失败。

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)
Run Code Online (Sandbox Code Playgroud)

  • 在 C++ 中以这种方式实现锁定/解锁序列很容易出错(在其他语言中也可能如此),因为它不是异常安全的。您可以使用 C++ 标准提供的 [`std:lock_guard`](http://en.cppreference.com/w/cpp/thread/lock_guard) 习惯用法之一,或者如果需要,可以轻松使用您自己的习惯用法! (3认同)