之前的笔记搬运
多线程操作共享资源时有什么问题?
多线程同时对一块共享资源时, 因为线程切换的问题就会造成数值结果不确定的后果,
所以就需要对共享资源的代码加锁操作;
用户态
如何对代码进行加锁呢?
- 原子操作(不常用)
原子操作就是不可拆分的操作, 表示指定高级指令要么不执行, 要么就会执行完;
Interlocked开头的都是原子操作;
1 | 方法: |
临界区(常用)
当有线程进入临界区段时,其他线程或是进程必须等待, 当线程退出之后其他线程才可以进去该临界区;
1 | 方法: |
内核态
内核对象中的同步
内核对象中的同步包括:事件、信号量、互斥对象、可等待定时器;
R3和R0的同步有什么区别
R0: 内核对象的同步则会从用户态切换到内核态,所以速度会比较慢, 但是可以跨进程;
R3 而用户态的对象同步只能在本进程中使用, 所以速度会快一点;
信号状态
1 | WaitForSingleObject(句柄,等待时间) |
上面两个函数就是检测信号状态的函数, 作用就是检测是否被锁的状态。
如果是signaled ,即“锁开的”,则继续执行。如果不是,则挂起当前线程,直到超过等待时间或者是该句柄变为signaled状态,系统会将线程恢复成可调度的状态。
几种内核态的线程同步方式
1) 事件(Enent)
1 | CreateEvent 创建一个事件 |
2) 信号灯
1 | CreateSemaphore 创建一个信号灯 |
当前资源计数器不会超过最大资源计数器,如果当前资源计数器(lInitialCount)值为0,那么信号量是未触发的状态,即“关门”的状态,所有的线程waitforsingleobject的时候,都会被挂起。
1 | ReleaseSemaphore 释放一个信号灯 |
如果资源计数器值大于0,则信号量就变为已触发的状态,那么就会从等待的线程中唤醒一个线程,当唤醒后,就会自动对当前资源计数器减1。
信号量可以限制访问共享资源的线程的个数
3) 互斥对象
1 | CreateMutex 创建互斥体 //在创建互斥体时, 如果本线程拥有这个互斥体的参数填TRUE时, 那么引用计数初始化就是为1 |
互斥对象包含一个使用数量,一个线程 I D和一个计数器
互斥对象用来确保一个线程独占一个资源(类似于临界区)。
线程ID用来标识当前占用这个互斥量的是系统中的哪个线程。
递归计数表示这个线程占用互斥量的次数
当一个线程获得了访问权,会将互斥体的线程ID设置为当前ID,记录线程拥有使用权,将互斥体的计数器置为1,状态变为未通知。
可多次调用WaitForSingleObject,每次调用递归计数器递加1。
调用ReleaseMutex,递归计数器递减1,直到为0的时,则互斥体状态变为已通知,可再唤醒一个等待该互斥体的线程。