控制线程

线程安全问题

clipboard (1).png

临界区的设计思路:

线程安全问题的产生,我认为主要是不能够确定两个或多个线程操作同一资源时(全局变量),是否已经操作完毕,而临界区的设计,就像要去上公共厕所的两个人,一个人进去上厕所时会锁门(发布一个令牌),另一个人去上厕所时因为门锁了就进不去了,只能等第一个人出来才能进去。

这样确定了一个线程执行操作代码完后另一个才能操作,不会出现一个线程要取出一个数 ++,结果刚取出这个数还没++,时间片已经结束(20ms),另一个线程也要取出这个数 ++,那么两个线程都 ++完后,实际上得到的数只加了一次,这不是我们想要的结果

临界区就像把一堆代码封装成一句代码.clipboard (2).png

临界区使用:

1、创建CRITICAL_SECTION:

CRITICAL_SECTION cs;

2、在使用前进行初始化

InitializeCriticalSection(&cs);

3、在函数中使用:clipboard (3).png

4、删除CRITICAL_SECTION

VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);

当线程不再试图访问共享资源时

 

 

怎么使用是合理的?

应当是操作一个全局变量,就定义一个令牌。

且该令牌的作用域仅停留在操作该全局变量的代码

 

产生死锁?

X,Y是两个线程  A,B是两个令牌

这样的代码是安全的:

clipboard (4).png

 

clipboard (5).png

 

而上面的代码不安全

当X线程执行到红色区域时,时间片(20s)结束,然后Y线程执行,拿走了令牌B

出现了X等着令牌B,Y等着令牌A,两个线程都无法执行,互相等待

 

 

阻塞(等待)函数

clipboard (6).png

功能说明:

等待函数可使线程自愿进入等待状态,直到一个特定的内核对象变为已通知状态为止.

hHandle:

内核对象句柄,可以是进程也可以是线程.

dwMilliseconds:

等待时间,单位是毫秒  INFINITE(-1)一直等待

返回值:

WAIT_OBJECT_0(0)                  等待对象变为已通知

WAIT_TIMEOUT(0x102)           超时

特别说明:

1、内核对象中的每种对象都可以说是处于已通知或未通知的状态之中

2、这种状态的切换是由Microsoft为每个对象建立的一套规则来决定的

3、当线程正在运行的时候,线程内核对象处于未通知状态

4、当线程终止运行的时候,它就变为已通知状态

5、在内核中就是个BOOL值,运行时FALSE 结束TRUE

 

群体阻塞(等待)函数

DWORD WaitForMultipleObjects(

 DWORD nCount,             // number of handles in array

 CONST HANDLE *lpHandles,  // object-handle array

 BOOL bWaitAll,            // wait option

 DWORD dwMilliseconds      // time-out interval

);

 

clipboard (7).png

 

clipboard (8).png

互斥体(Mutex)

创建互斥体:

HANDLE g_hMutex = CreateMutex(NULL,FALSE, "XYZ");

临界区的设计其实就是一种互斥

WaitForSingleObject(g_hMutex,INFINITE);       //等待(阻塞)函数  第二个参数:等待时间

INFINITE(宏)  == -1: 为一直等待

此时如果互斥体处于已通知状态,则停止阻塞,将互斥体转为未通知状态,并且该线程向后执行,获得控制权

而如果互斥体处于未通知状态,则一直阻塞直到转为互斥体转为未通知状态

//逻辑代码

ReleaseMutex(g_hMutex);    

使互斥体回到已通知状态,其他线程可以获得其控制权

clipboard (9).png

互斥体是一种内核对象

HANDLE g_hMutex = OpenMutex(MUTEX_ALL_ACCESS,FALSE, "XYZ");

//在其他进程访问该互斥体

 

 

 

事件

事件是一种内核对象(内核对象一旦创建,是在高2G内存空间中)

创建事件对象

HANDLE g_hEvent = CreateEvent(NULL, TRUE, FALSE, "XYZ");

参数说明:

第一个参数是安全属性,第二个参数是需要手动设置状态,即wait函数执行后不会改变通知状态,如果是false就会自动更改状态,第三个参数是通知状态初始值,false是未通知状态,true是已通知状态

事件对象的控制

BOOL SetEvent(HANDLE hEvent);     //改变为已通知状态

事件内核对象的获取

clipboard (10).png

HANDLE g_hEvent = OpenEvent(EVENT_ALL_ACCESS, FALSE, "XYZ");

clipboard (11).png

信号量

clipboard (13).png

关于句柄和ID

1、都是系统分配的一个编号,句柄是客户程序使用 ID主要是系统调度时使用.

2、调用CloseHandle关闭进程或者线程句柄的时候,只是让内核计数器减少一个,并不是终止进程或者线程.

进程或线程将继续运行,直到它自己终止运行。

3、进程ID与线程ID 是不可能相同。但不要通过进程或者线程的ID来操作进程或者线程,因为,这个编号是会重复使用的,也就是说,当你通过ID=100这个编号去访问一个进程的时候,它已经结束了,而且系统将这个编号赋给了另外一个进程或者线程.

posted @ 2021-03-29 21:10  Punished  阅读(70)  评论(0编辑  收藏  举报