一、并发的实现
1.多进程并发主要解决进程间通信的问题
①同一电脑上:管道、文件、消息队列、内存共享。
②不同电脑上:socket网络通信。
2. 单进程中的多个线程并发(一个主线程+多个子线程实现并发)
①一个进程中的所有线程共享内存空间 eg:全局变量,指针引用
二、线程的多种创建方式
1. 调用thread类去创建线程对象
头文件和子线程处理函数(以下所有代码段共用):
#include<iostream>
#include<thread>
#include<windows.h>
using namespace std;//线程处理函数
void print() {Sleep(3000);cout << "子线程运行喽........" << endl;
}
注:如果创建一个线程而不做处理,会调用abort函数中止程序
一个线程只能join一次,否则也会abort。
1.1. 使用join()函数加入,汇合线程,阻塞主线程,等待子进程执行结束,才会回到主线程
int main(){//创建线程thread test1(print);test1.join(); //阻塞(若test1线程未执行完,则主线程不会打印)cout << "主线程运行喽........." << endl;
}
运行说明:三秒后依次打印出
1.2. 使用detach()函数,打破依赖关系,把子线程驻留后台
注:线程detach后,就不能在join了
int main(){//创建线程thread test1(print);test1.detach();cout << "主线程运行喽........." << endl;
}
运行说明:直接只打印出:
1.3 使用joinable()函数判断当前线程是否可以做join或者detach操作,若可以,返回true。
int main(){//创建线程thread test1(print);test1.detach();cout << "主线程运行喽........." << endl;if (test1.joinable())test1.join();elsecout << "该子线程已经被处理啦....." << endl;
}
运行说明:
2. 通过类和对象创建线程
class Li {
public://STL仿函数void operator()() {cout << "子线程启动喽....." << endl;}
};
int main(){//正常写法:对象充当线程处理函数Li li;thread test1(li);test1.join();Li(); //无名对象thread test2((Li())); //这里如果不多写一个括号,编译器就会把test2解析成一个函数,Li()解析成一个参数,从而出错test2.join();}
运行:
3. 带参的方式创建线程
//传引用可以改变num的实际值
void printInfo(int& num) {cout << "子线程运行喽...." << endl;
}
int main(){int num = 0;//ref 用于包装 “引用传递值” thread test1(printInfo, ref(num));test1.join();cout << "我是主线程...." << endl;}
运行:
4. Lambda表达式创建线程
int Max(int a, int b) {return a > b ? a : b;
}
int main(){int (*pMax)(int, int) = nullptr;pMax = [](int a, int b)->int {return a > b ? a : b; };[] {cout << "helloword" << endl; }();cout << pMax(3, 5) << endl;thread test1([] {cout << "我是子线程..." << endl; });test1.join();cout << "我是主线程..." << endl;return 0;
}
运行:
5. 以智能指针为参数创建线程
void print(unique_ptr<int> ptr) {cout << "我是子线程:" << ptr.get()<<endl;
}
int main(){int* p = new int(100);unique_ptr<int> ptr(p);cout << "我是主线程:" << ptr.get() << endl;thread test1(print, move(ptr)); //move移动语义,通俗的说就是把ptr移动到子线程中了,这样的话,主线程中的ptr就没了 test1.join();cout << "我是主线程:" << ptr.get()<<endl;}
运行:
6. 以类的成员函数充当线程处理函数来创建线程
class Li {
public:void print(int& num) {num = 1001;cout << "我是子线程:" << this_thread::get_id() << endl;}
};
int main(){Li li;int num = 1007;//需要说明 是哪个对象thread test1(&Li::print,li,ref(num));test1.join();cout << "我是主线程:" << this_thread::get_id()<<endl;}
运行: