template<typename T>
class BlockQueue {
public:
BlockQueue(int cap) : cap_(cap) {
}
void put(const T &element) {
unique_lock<mutex> lock_(mutex_);
while (data_.size() == cap_) {
writeCond.wait(lock_);
}
data_.push(element);
readCond.notify_all();
}
T get() {
unique_lock<mutex> lock_(mutex_);
while (data_.empty()) {
readCond.wait(lock_);
}
T element = data_.front();
data_.pop();
writeCond.notify_all();
return element;
}
private:
int cap_;
queue<T> data_;
mutex mutex_;
condition_variable readCond;
condition_variable writeCond;
};
template<typename T>
class ProduceConsume {
private:
BlockQueue<T> blockQueue;
mutex outPutMutex;
public:
ProduceConsume(int buffSize) : blockQueue(buffSize) {
}
void produce() {
for (int i = 0; i < 5; ++i) {
auto element = rand();
blockQueue.put(element);
{
lock_guard<mutex> outPutLock(outPutMutex);
cout << "thread " << this_thread::get_id() << " put " << element << endl;
}
sleep(1);
}
}
void consume() {
for (int i = 0; i < 5; ++i) {
auto element = blockQueue.get();
{
lock_guard<mutex> outPutLock(outPutMutex);
cout << "thread " << this_thread::get_id() << " get " << element << endl;
}
sleep(1);
}
}
};
int main() {
{
ProduceConsume<int> produceConsume(3);
jthread produce(&ProduceConsume<int>::produce, std::ref(produceConsume));
jthread consume(&ProduceConsume<int>::consume, std::ref(produceConsume));
sleep(3);
cout << "main thread continue in jthread life scope..." << endl;
}
cout << "main thread continue out jthread life scope" << endl;
}
输出:
thread 140402881443584 put 1804289383
thread 140402881443584 put 846930886
thread 140402881443584 put 1681692777
main thread continue in jthread life scope...
thread 140402881443584 put 1714636915
thread 140402873050880 get 1804289383
thread 140402873050880 get 846930886
thread 140402873050880 get 1681692777
thread 140402873050880 get 1714636915
thread 140402873050880 get 1957747793
thread 140402881443584 put 1957747793
main thread continue out jthread life scope
问题:
(1) 代码使用了两把锁,会造成死锁吗
答案:不会。因为output锁是在blockqueue内部的锁释放之后,才使用的。不构成循环依赖
(2) 为何启动线程时:类的成员函数需要传地址,对象实例要传引用
答案:C++标准要求
(3) 为何jthread 没有Join,但主线程并未退出?
jthread对象在作用域快要结束时,会自动析构,在jthread的析构函数中调用了join。让他自己阻塞
直到jthread的任务函数执行完成之后,解除阻塞。主函数继续运行 (从程序的输出中也可以观察到这一点)