多线程意义:
单核cpu 系统会为每个线程分配一个时间片,时间片执行完了,就会让其他线程执行
多核cpu 系统会同时执行几个线程
单核:在主线程中创建一个子线程,创建完了,子线程为什么没有执行。因为主线程还在时间片内,所以不会执行子线程。
时间片内主线程会一直执行,直到执行完返回,主线程即进程,执行完了,所有的资源和线程都会被关闭,所以创建的线程就不会执行。
怎么才能让创建完的子线程执行呢?
我们只需 sleep(100) sleep一个时间,主线程这段时间就不会执行,新建的子线程就会执行。执行完会返回到主线程,主线程继续执行。
如果是多核的话:不需要sleep 创建的线程也会执行。
如果分配给线程的时间片到期了,执行权力就会给其他线程。就会断掉,但是系统会记录断掉的位置,任何地方都有可能断,不管是循环或是判断语句,其他的线程执行完了,就会返回给当前线程,接着刚才的地方执行。所以这里很容易出现问题,比如变量的值或其他已经改变,这里没做处理就会出来问题。
模拟这种断,只需要在想断的地方加入sleep(1) 就可以断掉
所以这里就涉及到线程之间数据同步
互斥对象
用法:创建一个互斥对象,waitForsignalObject(等待一个互斥对象),release(释放一个互斥对象),等待一个互斥对象如果该互斥对象被其他线程拥有,该线程就会等待不会执行(这里的等待,应该会等待,直到时间片执行完毕,另个线程会继续执行),直到互斥对象可以使用时才会继续向下执行。 等待一个互斥对象,一般放在保护代码的前面,release一般放在关键的代码执行完毕的时候。
互斥对象的管理:是通过引用计数来管理的,当期线程拥有该互斥对象,还调用waitfor... 就会使互斥对象+1,
互斥对象释放,只有当前线程(因为互斥对象记录了当前线程的ID)才能释放。释放之后-1, 为0之后就不会拥有该互斥对象,这时互斥对象就处于有信号状态。 如果该线程结束(主动结束或返回),就会释放互斥对象。 waitfor..的返回值,可以判断该互斥对象是异常终止还是主动终止。
可以利用互斥对象,来限制只能有一个程序运行。
事件对象
分为人工重置事件对象,与自动重置事件对象
人工重置事件对象,有信号状态后,会调度所有的等待线程,当前线程获得当前事件对象,需要手动设置事件对象的信号
自动重置事件对象,有信号状态后,只会调度一个线程,操作系统会自动把事件对象设置为无信号,只需在需要的地方设置有信号就可以了。
关键代码段(临界区)
EnterCriticalSection等待临界区(判断是否可用,可用获取临界区)
InitializeCriticalSection 初始化临界区
LeaveCriticalSection 离开临界区
DeleteCriticalSection 释放临界区
线程死锁
两个线程,有两个临界区(互斥对象或事件对象),
线程1
EnterCriticalSection(A)
sleep(1) 模拟出错
EnterCriticalSection(B)
线程2
EnterCriticalSection(B)
sleep(1) 模拟出错
EnterCriticalSection(A)
这样就造成了死锁
线程1获取A 取得A的拥有权 sleep(1) 会让线程2执行 线程2获得B的所有权
sleep(1) 线程1执行 线程1接着执行,等待B信号, 但是B信号已经被线程2拥有 所以他取得不到 然后一直等待
线程2继续执行 等待A信号,但是A信号被线程1拥有,所以他将一直等待下去
这样程序就不会继续执行了 造成死锁
3种同步方式区别
参考:孙鑫vc++视频 15 16课
版权声明:本文为博主原创文章,未经博主允许不得转载。