一、进程与线程的区别
1.进程是操作系统进行资源调度和分配的基本单位,线程是操作系统可执行的最小调度和分配单位
2.一个线程属于一个进程,一个进程可以有多个线程
3.一个进程崩溃不影响其他进程,但是一个线程崩溃会让进程崩溃
4.进程在执行过程中有独立的存储单元,而线程之间共享进程的内存
进程之间切换系统开销大,而线程之间切换开销比进程小
二、多线程
线程:
线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,进程包含一个或者多个线程。进程可以理解为完成一件事的完整解决方案,而线程可以理解为这个解决方案中的的一个步骤,可能这个解决方案就这只有一个步骤,也可能这个解决方案有多个步骤。
多线程:
多线程是实现并发(并行)的手段,并发(并行)即多个线程同时执行,一般而言,多线程就是把执行一件事情的完整步骤拆分为多个子步骤,然后使得这多个步骤同时执行。
C++多线程:(简单情况下)C++多线程使用多个函数实现各自功能,然后将不同函数生成不同线程,并同时执行这些线程(不同线程可能存在一定程度的执行先后顺序,但总体上可以看做同时执行)。
三、线程创建方式
#include <iostream>
#include <thread>
using namespace std;
void show(){
}
int main(){
thread my_thread(show,1);
my_thread.join();
return 0;
}
join(), 当前线程暂停, 等待指定的线程执行结束后, 当前线程再继续。my_thread.join();,即该语句所在的线程(该语句写在main()函数里面,即主线程内部)暂停,等待指定线程(指定线程为my_thread.join();执行结束后,主线程再继续执行。my_thread.join();
四、线程互斥锁
lock()与unlock()
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex m;//实例化m对象,不要理解为定义变量
void th1(int a)
{
m.lock();
cout << "th1函数正在改写a" << endl;
cout << "原始a为" << a << endl;
cout << "现在a为" << a + 100 << endl;
m.unlock();
}
void th2(int a)
{
m.lock();
cout << "th22函数正在改写a" << endl;
cout << "初始始a为" << a << endl;
cout << "现在a为" << a + 200<< endl;
m.unlock();
}
int main()
{
int a = 0;
thread th1(proc1, a);
thread th22(proc2, a);
th1.join();
th2.join();
return 0;
}
lock_guard()
其原理是:声明一个局部的lock_guard对象,在其构造函数中进行加锁,在其析构函数中进行解锁。最终的结果就是:创建即加锁,作用域结束自动解锁。从而使用lock_guard()就可以替代lock()与unlock()。
include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex m;//实例化m对象,不要理解为定义变量
void th1(int a)
{
{
lock_guard<mutex> g1(m);
cout << "th1函数正在改写a" << endl;
cout << "原始a为" << a << endl;
cout << "现在a为" << a + 100 << endl;
m.unlock();
}//出了作用域自动解锁,不需要再调用unlock();
}
void th2(int a)
{
lock_guard<mutex> g1(m);
cout << "th2函数正在改写a" << endl;
cout << "初始始a为" << a << endl;
cout << "现在a为" << a + 200<< endl;
m.unlock();
}
int main()
{
int a = 0;
thread th1(proc1, a);
thread th22(proc2, a);
th1.join();
th2.join();
return 0;
}
lock_gurad也可以传入两个参数,第一个参数为adopt_lock标识时,表示不再构造函数中不再进行互斥量锁定,因此此时需要提前手动锁定。
例如:
void th1()
{
m.lock();//手动锁定
lock_guard<mutex> g1(m,adopt_lock);//不需要加unlock()。
}
unique_lock:
unique_lock类似于lock_guard,只是unique_lock用法更加丰富,同时支持lock_guard()的原有功能。
使用lock_guard后不能手动lock()与手动unlock();使用unique_lock后可以手动lock()与手动unlock();
unique_lock的第二个参数,除了可以是adopt_lock,还可以是try_to_lock与defer_lock;
try_to_lock: 尝试去锁定,得保证锁处于unlock的状态,然后尝试现在能不能获得锁;尝试用mutx的lock()去锁定这个mutex,但如果没有锁定成功,会立即返回,不会阻塞在那里
defer_lock: 始化了一个没有加锁的mutex;
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex m;
void proc1(int a)
{
unique_lock<mutex> g1(m, defer_lock);//始化了一个没有加锁的mutex
cout << "不拉不拉不拉" << endl;
g1.lock();//手动加锁,注意,不是m.lock();注意,不是m.lock();注意,不是m.lock()
cout << "proc1函数正在改写a" << endl;
cout << "原始a为" << a << endl;
cout << "现在a为" << a + 2 << endl;
g1.unlock();//临时解锁
cout << "不拉不拉不拉" << endl;
g1.lock();
cout << "不拉不拉不拉" << endl;
}//自动解锁
void proc2(int a)
{
unique_lock<mutex> g2(m,try_to_lock);//尝试加锁,但如果没有锁定成功,会立即返回,不会阻塞在那里;
cout << "proc2函数正在改写a" << endl;
cout << "原始a为" << a << endl;
cout << "现在a为" << a + 1 << endl;
}//自动解锁
int main()
{
int a = 0;
thread proc1(proc1, a);
thread proc2(proc2, a);
proc1.join();
proc2.join();
return 0;
}
unique_lock所有权的转移
mutex m;
{
unique_lock<mutex> g2(m,defer_lock);
unique_lock<mutex> g3(move(g2));//所有权转移,此时由g3来管理互斥量m
g3.lock();
g3.unlock();
g3.lock();
}
condition_variable:
需要#include<condition_variable>;
wait(locker):在线程被阻塞时,该函数会自动调用 locker.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数此时再自动调用 locker.lock()。
notify_all():随机唤醒一个等待的线程
notify_once():唤醒所有等待的线程
五、线程池