多线程,并发安全与volatile
本文可能涉及到的一些知识,std::thread,线程同步互斥量,线程通信条件变量,线程安全的院子变量,call_once,异步操作,线程安全
volatile类型修饰符(类型修饰符:例如const)
(用于修饰被不同线程访问和修改的变量,作为指令关键字,确保本条指令不会因为编译器的优化而省略,且要求每次直接读值)
例如:并行设备的硬件寄存器,一个中断服务子程序中会访问到的非自动变量,多线程应用中被几个任务共享的变量
使用:volatile int a;
线程的生存周期
new->runable->running->blocked->time waiting->waiting->dead
线程类型形式(include”thread” env(C++))
创建线程
std::thread t(
func
,param1
,param2
);
(仍可容易创建形如bind()与lambda线程函数)
//实际上并不喜欢这种创建之后直接执行的线程形式,或者是我了解不够,在JAVA中此类得到了改善,拥有独立的start()
线程操作
阻塞(即等待线程完结):t.join();
reload->t.join(long millis) t.join(long millis,int nanoseconds)
分离线程:t.detach(); //生命周期不可预计
移动线程:std::thread t1(std::move(t));
取得线程ID:std::this_thread::get_id()
等待:std::this_thread::sleep_for(chrono)
线程的WINAPI形式(由微软在Windows API中提供)
创建新线程
MSDN中CreateThread原型:
HANDLE CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes,//指向SECURITY_ATTRIBUTES形态的结构指针
SIZE_T dwStackSize,//initialstacksize //初始栈大小空间,0为与函数的线程大小相同的栈
LPTHREAD_START_ROUTINE lpStartAddress,//ThreadPoint 声明形式:DWORD WINAPI function(LPVOID lpParam)
/*
可选择参数类型void:
lpStartAddress:(LPTHREAD_START_ROUTINE)Myvoid
线程声明:
void Myvoid()
{
return;
}
*/
LPVOID lpParameter,//threadParam
DWORD dwCreationFlags,//CREATE_SUSPENDED/0/STACK_SIZE_PARAM_IS_A_RESERVATION
LPDWORD lpThreadId//threadidentifier
)
processthreadsapi.h中CreateThread原型:
WINBASEAPI
_Ret_maybenull_
HANDLE WINAPI CreateThread(
_In_opt_LPSECURITY_ATTRIBUTES lpThreadAttributes,
_In_SIZE_T dwStackSize,
_In_LPTHREAD_START_ROUTINE lpStartAddress,
_In_opt___drv_aliasesMemLPVOID lpParameter,
_In_DWORD dwCreationFlags,
_Out_opt_LPDWORD lpThreadId
);
关闭线程
Bool CloseHandle(HANDLE hObject);
(可用于关闭多种具有句柄的对象)
常见的其他线程开始关闭对
RTL库System单元
BeginTHread()
MFC
AfxBeginThread()
Visual C++
_beginThread()
_endThread()
事件
(通过通知操作的方式保持线程同步,并可以实现不同进程中的线程同步操作)
相关函数
CreateEvent() //创建一个信号量
OpenEvent() //打开一个事件
SetEvent() //回置事件
WaitForMultipleObject() //等待一个事件
WaitForMultipleObjects(IN DWORD nCount, //等待句柄数
IN CONST HANDLE* IpHandles, //指向句柄数组
IN BOOL bWaitAll, //是否完全等待标志
IN DWORD dwMilliseconds) //等待时间
//等待多个事件
(return(超时)WAIT_TIMEOUT)
```
****
****
## 信号量
(信号允许多个线程同时使用共享资源(如同操作系统中的PV操作),同时指出了同时访问的最大量(最大资源计数))
### 线程操作
CreateSemaphone() //创建一个信号量
OpenSemaphone() //打开一个信号量(同加锁)
ReleaseSemaphone() //释放信号量(同解锁)
WaitForSingleObject() //等待信号量(同延时锁)
(进程与线程在退出前处于无信号状态,在退出后会处于有信号状态,可以使用WaitForSIngleObject()来等待进程和线程退出)
****
****
## 临界区
(提供独占式访问,工作于用户级)
### 相关函数
void InitializeCriticalSection(LPCRITICAL_SECTION IpCriticalSection) //初始化临界区
void EnterCriticalSection(LPCRITICAL_SECTION IpCriticalSection) //进入临界区
void LeaveCriticalSection(LPCRITICAL_SECTION IpCriticalSection) //离开临界区
void DeleteCriticalSection(LPCRITICAL_SECTION IpCriticalSection) //释放临界区资源
(临界区使用为防止失误常使用封装的方式进行,以对象的生命周期控制临界区范围)
****
****
## 互斥量--`<mutex>`
(一种同步原语,线程同步手段,保护多线程同时访问的共享数据,互斥量的争夺实际上就是对其所有权的争夺,线程优先级影响争夺线程的结果,可以命名,标志着可以跨进程使用)
分类:
**std::mutex:独占互斥量,不能递归使用**
**std::timed_mutex:具有超时的独占互斥量,不能递归使用**
(递归锁定复杂度高,效率低下爱,并非不可优化,且有未标明的最大次数限制)
**std::recursive_mutex:递归互斥量(允许统一线程多次获得同一互斥量),不具有超时**
**std::recursive_timed_mutex:不做解释**
(ps:4种互斥量在循环中除mutex均不会产生join())
### 基本操作
lock()
unlock()
try_lock()
timed_mutex::try_lock_for(chrono)
### RAII技术*lock_guard/unique_lock
std::lock_guard<std::mutex> locker(g_lock); //出作用域自动解锁(析构)
std::unique_lock<std::mutex> locker(g_lock); //可随时释放线程锁,而非需要等待对象生命周期结束
### 条件变量--`<condition_variable>`
**condition_variable,配合std::unique_lock<std::mutex>进行wait()操作**
std::unique_lock()--可以自由的释放mutex而非需要等待对象生命周期结束
**condition_variable_any,和任意带有lock(),unlock()语义的mutex搭配使用,比较灵活但是效率较差**
含有函数:
condition_variable::wait(std::mutex)
(该函数接受重载:condition_variable::wait(mutex,lambda/function*))
(唤起线程)condition_variable::notify_one()/notify_all()
### 原子变量--`atomic`
类型说明:std::atomic<T>
--读取修改会写变为不可打断的操作
usual_use--`atomic::load()`
(return Value)
****
### call_once/once_flag的使用
(保证多线程环境中函数仅被调用一次)
>std::call_once(`once_flag`,`Funtion`);
(once_flag设置作用于决定该独有性的区间)
****
****
## 异步操作
### 异步操作类
#### std::future
(使用同步等待的方式来获取异步操作的结果)
Get:
get() //等待并返回结果
wait() //等待
wait_for(std::chrono) //超时等待返回结果
Return:
Deferred //异步操作还未开始
Ready //已完成
Timeout //异步操作超时
**future本身不渴拷贝,shared_future则可以拷贝放入容器**
****
#### std::promose
(绑定数据和future,线程将为外部传入(参数)的promise赋值)
Get:
std::promise ptr;
std::thread t(std::promise& p)
{p.set_value_at_thread_exit(9);},std::ref(ptr));
std::future f= ptr.get_future();
auto r=f.get();
****
#### std::package_task
(包装了一个可以调用对象的包装类,将函数和future绑定起来)
Get:
std::packaged_task
### 异步操作函数async
(async比future,packed_task,thread等更高一级,可以直接创建异步的task,异步任务的返回结果也保存在future中)
>**async(std::launch::async|std::launch::deffered,f,args...)**
param:
创建线程的策略
std::launch::async //在调用async时就创建线程
std::launch::deffered //延迟加载方式创建线程————直到调用了future的get或者wait时才创建线程
线程函数
线程函数参数
“`