多线程
1,头文件
#include <thread>
2,调用thread类创建线程(右击--转到定义,可见thread上一个类),同时直接传递线程函数或者创建线程的类对象。
线程的创建方式
函数创建线程
类/结构体对象创建线程
struct fang {
void operator()() {
cout << "create thread..." << endl;
}
};
int main() {
fang threadF;
thread func(threadF);
if(func.joinable())
func.detach();
return 0;
}
因为lambda返回的是函数指针,所以也可以
lambda函数创建线程
thread thread1([] {
int a = 100, b = 122;
cout << a + b << endl;
});
thread1.join();
参数传递创建线程
注意:多个参数都可以传递
void add(int a, int b) {
a++;
cout << a + b;
}
int main() {
int a = 10, b = 2;
thread thread2(add,a,b);
thread2.join();
return 0;
}
指针传递创建线程
void add(int* a, int* b) {
(*a)++;
cout << *a + *b;
}
int main() {
int a = 10, b = 2;
thread thread2(add,&a,&b);
thread2.join();
return 0;
}
引用参数传递创建线程
注意:如果参数是引用,需要用std::ref函数包装才可以传递
void add(int& a, int& b) {
a++;
cout << a + b;
}
int main() {
int a = 10, b = 2;
thread thread2(add,std::ref(a),std::ref(b));
thread2.join();
return 0;
}
有智能指针作为参数的线程函数
智能指针要用move转为右值
void add3(unique_ptr<int> ptr) {
cout << "子线程:" << ptr.get() << endl;
}
int main() {
unique_ptr<int> ptr(new int(100));
cout << "主线程:" << ptr.get() << endl;
thread thread3(add3,move(ptr));
thread3.join();
cout << "指针对象move之后不存在:" << ptr.get() << endl;
return 0;
}
类成员函数创建线程
使用类成员函数创建的线程,不同线程可以共享一个类的成员对象吗?
#include <iostream>
#include <thread>
#include <unistd.h>
class Test{
public:
void run(int v){
setValue(v);
sleep(5);
std::cout<<"sub thread value="<<value<<std::endl;
}
void setValue(int v){
value=v;
}
int getValue(){
return value;
}
private:
int value{10};
};
Test t2;
int main(){
Test t1;
std::thread sub_thread(&Test::run,t1,100);
sub_thread.join();
std::cout<<"main thread1 vlaue="<<t1.getValue()<<std::endl;
std::thread sub_thread2(&Test::run,t2,100);
sub_thread2.join();
std::cout<<"main thread2 vlaue="<<t2.getValue()<<std::endl;
return 0;
}
结果表明无论类对象是全局还是局部对象子线程和主线程并不共享同一个类的成员和成员函数。
原因:
这段代码中,类对象t1是参数,参数的传递本质上是值拷贝。指定t1为子线程的参数,那么创建子线程的时候就会创建一个临时的Test类对象,只是这个类对象拷贝t1对象的数据而已,所以子线程中操作的是临时对象,而不是t1对象。
如何让子线程和主线程操作同一个类对象?
解决办法:
t1对象指定为指针传递或者引用传递即可。
#include <iostream>
#include <thread>
#include <unistd.h>
class Test{
public:
void run(int v){
//setValue(v);
sleep(2);
std::cout<<"sub thread value="<<getValue()<<std::endl;
}
void setValue(int v){
value=v;
}
int getValue(){
return value;
}
private:
int value{10};
};
int main(){
Test t1;
t1.setValue(111);
std::thread sub_thread(&Test::run,&t1,100); //指针
sub_thread.join();
std::cout<<"main thread1 vlaue="<<t1.getValue()<<std::endl;
return 0;
}
在类的函数中开启另一个线程对类进行操作
#include <iostream>
#include <thread>
#include <unistd.h>
class Test{
public:
void init(){
std::thread th(&Test::run,this,111);
th.join();
std::cout<<"main address="<<this<<std::endl;
std::cout<<"main thread1 vlaue="<<getValue()<<std::endl;
}
void run(int v){
setValue(v);
sleep(2);
std::cout<<"sub address="<<this<<std::endl;
std::cout<<"sub thread value="<<getValue()<<std::endl;
}
void setValue(int v){
value=v;
}
int getValue(){
return value;
}
private:
int value{10};
};
int main(){
Test t1;
t1.init();
return 0;
}
相同的地址,相同的值。
vector容器的emplace_back()函数创建线程
vector<thread> vecThread;
int a = 10, b = 23;
for (int i = 0; i < 5; ++i) {
vecThread.emplace_back(add, a, b);
vecThread[i].join();
}
joint和detach
joint和detach可以都调用吗
不可以。
#include <iostream>
#include <thread>
#include <unistd.h>
class Test{
public:
void init(){
std::thread th(&Test::run,this);
th.detach();
int time=0;
std::cout<<"main address="<<this<<std::endl;
while(run_flag_){
time++;
if(time==5) run_flag_=false;
sleep(1);
}
std::cout<<"main thread1 vlaue="<<getValue()<<std::endl;
th.join();//执行到这的时候报错--system_error
}
void run(){
std::cout<<"sub address="<<this<<std::endl;
while(run_flag_){
setValue();
std::cout<<"sub thread value="<<getValue()<<std::endl;
sleep(1);
}
}
void setValue(){
value++;
}
int getValue(){
return value;
}
private:
int value{10};
bool run_flag_{true};
};
int main(){
Test t1;
t1.init();
return 0;
}
原因:
detach已经分离了主线程和子线程的依赖关系,后续joint就joint不到了。
互斥锁
头文件
#include <mutex>
不同于linux,这个mutex创建对象之后就可以使用,不需要初始化。
线程同步是为了有序操作公共资源或者保护公共资源
try_lock()
尝试加锁,如果锁已经被锁,返回false,所以try_lock()需要对是否上锁成功做判断
条件变量--condition_varieble
wait(unique_lock<mutex>)
阻塞当前线程直到条件变量被唤醒;
unqiue_lock<mutex>
作用:自动或者调用lock获取并上锁,作用域结束时自动释放互斥锁;
unique_ lock提供了以下几种加锁和解锁方式: .
1.默认构造函数创建一个未加锁的unique_ lock对象, 可以通过调用其成员函数lock()来手动加锁,通过unlock()来手动解锁。
2.使用构造函数传入互斥量,并加锁。
3.使用构造函数传入互乐量,但不自动加锁,可以通过调用其成员函数try_ _lock()来尝 试加锁,如果成功返回true,失败返回false。
4.可以通过传入st.:adopt_ lock参 数来构造unique_ lock对象, 表示对已经加锁的互斥进行管理。
unique_lock和lock_guard都是管理锁的辅助类工具,都是RAII风格;它们是在定义时获得锁,在析构时释放锁。
notify_all()
作用:唤醒所有等待这个条件变量的线程;
notify_one()
作用:唤醒一个等待这个条件变量的线程;
三个线程A、B、C分别打印1-100,A打印3的倍数,B打印5的倍数,C打印其他数。不能重复
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
mutex m_mutex;
condition_variable cond;
int n = 1;
void printA() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (n % 3 == 0) {
cout<<"A:" << n << endl;
n++;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
void printC() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (n % 3 != 0 || n % 5 != 0) {
cout <<"C:" << n << endl;
n++;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
void printB() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (n % 5 == 0) {
cout <<"B:" << n << endl;
n++;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
int main() {
thread t1(printA),t2(printB),t3(printC);
t1.join();
t2.join();
t3.join();
return 0;
}
三个线程A,B,C,循环按序输出1,2,3一直输出到100
方法1:使用一个条件变量,,三个bool标志
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
mutex m_mutex;
condition_variable cond;
bool p1 = false , p2 = false, p3 = false;
int n = 0;
void printA() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p1) {
cout<<1<< endl;
n++;
p1 = false;
p2 = true;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
void printC() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p2) {
cout <<2<< endl;
n++;
p2 = false;
p3 = true;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
void printB() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p3) {
cout <<3<< endl;
n++;
p3 = false;
p1 = true;
cond.notify_all();
}
else {
cond.wait(lck);
}
}
}
int main() {
p1 = true;
thread t1(printA),t2(printB),t3(printC);
t1.join();
t2.join();
t3.join();
return 0;
}
方法2:各自线程使用各自的条件变量,三个标志
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>
using namespace std;
mutex m_mutex;
condition_variable cond1,cond2,cond3;
bool p1 = false , p2 = false, p3 = false;
int n = 0;
void printA() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p1) {
cout<<1<< endl;
n++;
p1 = false;
p2 = true;
cond2.notify_all();//唤醒线程2
}
else {
cond1.wait(lck);//线程1等待
}
}
}
void printC() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p2) {
cout <<2<< endl;
n++;
p2 = false;
p3 = true;
cond3.notify_all();
}
else {
cond2.wait(lck);
}
}
}
void printB() {
while (n <= 100) {
unique_lock<mutex> lck(m_mutex);
if (p3) {
cout <<3<< endl;
n++;
p3 = false;
p1 = true;
cond1.notify_all();
}
else {
cond3.wait(lck);
}
}
}
int main() {
p1 = true;
thread t1(printA),t2(printB),t3(printC);
t1.join();
t2.join();
t3.join();
return 0;
}