关于std::thread以及std::condition_variable的一些细节备忘

 2023-09-10 阅读 24 评论 0

摘要:  也算是看过不少多线程相关的资料了,但是一直对于其中的一些细节没有太好的把握,比如std::thread线程真正开始运行的时机,比如join、detch等真正的作用。 跟着《Cplusplus Concurrency In Action_Practical Multithreading》又过了一遍相关的细节

  也算是看过不少多线程相关的资料了,但是一直对于其中的一些细节没有太好的把握,比如std::thread线程真正开始运行的时机,比如join、detch等真正的作用。

跟着《Cplusplus Concurrency In Action_Practical Multithreading》又过了一遍相关的细节,下面记录一下一些个人所获得的收获。

std::thread真正开始运行的时机

std::vector,下面是我尝试写的一个基于条件变量和互斥量的生产者消费者模型的Demo,就从这里开始说起

#include<iostream>
#include<thread>
#include<unistd.h>
#include<vector>
#include<mutex>
#include<condition_variable>
#include<cmath>std::vector<int> resource;
std::mutex m;
std::condition_variable cv;void thread_procedure(){while(true){int n;while(true){std::unique_lock<std::mutex> ul(m);cv.wait(ul,[&]{return !resource.empty();});if(!resource.empty()) {n = resource.back();resource.pop_back();break;}}int res = 0;for(int i = 0; i<n; ++i){//sleep(2);res+=i;}std::lock_guard<std::mutex> ll(m);std::cout<<"This is from Thread "<<std::this_thread::get_id()<<", "<<"The sum of 0+1+2+...+"<<n<<" is "<<res<<std::endl;}
}int main(){std::thread tt[5];for(int i = 0; i<5; ++i){tt[i] = std::thread(thread_procedure);}for(int i = 0; i<5; ++i){tt[i].join();}while(true){std::lock_guard<std::mutex> lg(m);resource.push_back(rand()%100);cv.notify_one();}
}

这段代码使用了一个std::mutex和一个std::condition_variable控制相应的线程,尝试实现一个简单的打印功能。

但在运行时该代码会卡在生产者处,即join代码之后的while循环不会运行下去。。。

std::thread用法,这里几乎就涉及了std::thread线程库里面对于线程启动的机制以及join的真正语义了。

下面是一段GNU对于std::thread的实现代码:

class thread
{...
public:thread() noexcept = default;thread(thread&) = delete;thread(const thread&) = delete;thread(thread&& __t) noexcept{ swap(__t); }template<typename _Callable, typename... _Args>explicit thread(_Callable&& __f, _Args&&... __args){_M_start_thread(_M_make_routine(std::__bind_simple(std::forward<_Callable>(__f),std::forward<_Args>(__args)...)));}...
};

可以看到thread的构造函数传入了一个_Callable可调用对象以及相关的参数,然后使用了std::__bind_simple进行了包装,相当于std::bind,然后使用_M_start_thread直接使用平台相关线程实现开启了这个线程!

std::variant。从这里我们可以看出在每个std::thread构造完成的时候新线程就已经开启了

而join函数的作用就是等待join的线程执行结束,在join返回之后继续运行后续代码。

这样上面的代码会卡住也就理所应当了,在开启新线程之后资源池就用完了,然后启动的线程都阻塞在条件变量上面,而后续的while循环里面的生产过程则是由于join函数在等待已经开启的线程结束而无法运行。

sewing thread。整个程序就会在所有线程都处于阻塞状态下停在那里。

而解决这个问题的方法倒也简单,另开一个生产者线程就行,如下代码:

#include<iostream>
#include<thread>
#include<unistd.h>
#include<vector>
#include<mutex>
#include<condition_variable>
#include<cmath>std::vector<int> resource;
std::mutex m;
std::condition_variable cv;void thread_procedure(){while(true){int n;while(true){std::unique_lock<std::mutex> ul(m);cv.wait(ul,[&]{return !resource.empty();});if(!resource.empty()) {n = resource.back();resource.pop_back();break;}}int res = 0;for(int i = 0; i<n; ++i){res+=i;}std::lock_guard<std::mutex> ll(m);std::cout<<"This is from Thread "<<std::this_thread::get_id()<<", "<<"The sum of 0+1+2+...+"<<n<<" is "<<res<<std::endl;}
}void producer(){while(true){std::lock_guard<std::mutex> lg(m);resource.push_back(rand()%100);cv.notify_one();}
}int main(){std::thread tt[6];for(int i = 0; i<5; ++i){tt[i] = std::thread(thread_procedure);}tt[5] = std::thread(producer);for(int i = 0; i<6; ++i){tt[i].join();}
}

这种情况下,所有工作线程都在join函数调用之前就开启了,也就不会存在上述问题了。

pthread和thread?转载于:https://www.cnblogs.com/J1ac/p/9813955.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/5/36535.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息