创建一个多线程
// An highlighted block
#include<iostream>
#include<thread>
using namespace std;
void func(){
cout << "hello world \n" ;
}
int main(){
thread t1(func);
cout << "thread id:" << t1.get_id() << endl;
cout << "max thread nums:" << t1.hardware_concurrency() << endl;
t1.join();
}
通过thread类实例化一个对象,再加上对象t1.join()就可以创建一个新的线程,可以通过get_id方法查找到当前使用的id,通过hardware_concurrency()获取线程最大并发数量。
线程锁
案例1
// An highlighted block
#include<iostream>
#include<thread>
#include<chrono>
using namespace std;
int globVariable = 0;
void task1(){
for(int i = 0; i< 10000000;i++){
globVariable++;
globVariable--;
}
}
int main(){
int a = 0;
thread thread1(task1);
thread thread2(task1);
thread1.join();
thread2.join();
cout << globVariable << endl;
}
程序执行的结果理论上应该是0,但是实际执行的结果多种多样是一个不确定的数,这是因为对于公共变量,两个线程都进行了操作,因此会出现一定的问题。因此我们需要对线程上锁,即在该线程执行的过程中,其他线程对公共的变量都不能进行操作。
mutex互斥量
// An highlighted block
#include<iostream>
#include<thread>
#include<chrono>
#include<mutex>
using namespace std;
mutex mtx;
int globVariable = 0;
void task1(){
for(int i = 0; i< 10000000;i++){
mtx.lock();
globVariable++;
globVariable--;
mtx.unlock();
}
}
int main(){
int a = 0;
thread thread1(task1);
thread thread2(task1);
thread1.join();
thread2.join();
cout << globVariable << endl;
}
手动上锁解锁存在的问题,可能会出现死锁现象的发生
死锁产生的必要条件
互斥条件:进程要求对所分配的资源进行排它性控制,即在一段时间内某资源仅为一进程所占用。
请求和保持条件:当进程因请求资源而阻塞时,对已获得的资源保持不放。
不剥夺条件:进程已获得的资源在未使用完之前,不能剥夺,只能在使用完时由自己释放。
环路等待条件:在发生死锁时,必然存在一个进程–资源的环形链。
解决死锁的方法
unique_lock<mutex>lock(mtx);
lock_guard<mutex>lock(mtx);
以上两者方式都可以不再手动unlock,因此一定程度上避免死锁现象发生,其中unique_lock方法可以兼顾手动解锁方法。
atomic原子变量
直接定义公告的资源为原子变量,这样在多线程调用原子变量时就不在死锁。
std::atomic<int> globVariable = 0;
condition_variable条件变量
为了保证线程安全,在调用线程的时候有时候需要使用条件变量防止线程操作过程中的问题,如下程序可知,我们定义一个生产者和消费者,顾名思义,如果生成者还未生产出产品,消费者无法消费,我们需要使得消费者进行等待,不然程序就会报错这里在生产者端增加一个condit.notify_all()方法(这个方法在多个消费者也可以使用),再消费者端增加一个condit.wait(lock)就可以解决问题。
#include<iostream>
#include<thread>
#include<mutex>
#include<deque>
#include<condition_variable>
using namespace std;
deque<int> q;
mutex mtx;
condition_variable condit;
//producer
void task1(){
int i = 0;
while(true){
unique_lock<mutex> lock(mtx);
q.push_back(i);
condit.notify_one();
// this_thread::sleep_for(chrono::milliseconds(10));
if(i < 99999){
i++;
}
else {
i = 0;
}
}
}
//consumer
void task2(){
int data = 0;
while(true){
unique_lock<mutex>lock(mtx);
if(q.empty()){
condit.wait(lock);
}
data = q.front();
q.pop_front();
cout << "Get value from que:" << data << endl;
}
}
void task3(){
int data = 0;
while(true){
unique_lock<mutex>lock(mtx);
if(q.empty()){
condit.wait(lock);
}
data = q.front();
q.pop_front();
cout << "Get value from que:" << data << endl;
}
}
int main(){
thread t1(task1);
thread t2(task2);
thread t3(task3);
t1.join();
t2.join();
t3.join();
}