线程同步

来源:互联网 发布:suse linux官网 编辑:程序博客网 时间:2024/06/06 23:52

最进看了下windows编程,为 了能学点东西不 至于这么快忘记所以 赶忙记下几点:


先弄清楚的概念:

当进程正在运行时,进程内核对象处于未通知状态(未受信)。当进程停止运行时,就处于已通知状态(受信)


1.线程同步问题:

   在多线程中可能有很多个线程在执行同一段代码或者修改同一段内存,如果都只是读还好,但是要是同时读和写那么就会出问题导致 数据错乱。

比如两个全局变量都是自加两个线程同时调用这 两个 变量的自加函数问题来了,当一个线程 取出其中一个变量比如a好了,正要进行++a的时候它的时间片用完了 (时间片 待会 查查)另一个时间片轮到另一个线程开始执行了相同的++a后再轮到第一个线程执行第二个线程执行前拿到的a开始++a这就覆盖了第二个线程刚++a的值了导致a的结果 错乱了

解决这 个问题的办法:

一.使用临界区对象

 临界区对象是定义在数据段中的一个CRITICAL_SECTION 的结构,windows内部使用这个 结构记录一些信息,确保在同一个时间段内只有 一个线程 访问该数据段中的数据

编程之前要把临界区对象定义在想保护数据段中然后在任何线程 中使用此岭街去对象之前对它进行初始化

void InitializeCriticalSection(LPCRITICAL lpCriticalSection);

void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 进入零界区 一次只能一个线程 进去,其他线程等待该线程离开零界区

void LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) 离开零界区 一边给其他线程使用

void DeleteCriticalSection(LPCRITICAL_SECTION ) 不要用零界区 的时候要 删掉该零界区

零界区对象能够 很好 的保护 共享数据,但是 它不能够 用于 进程 之间资源的锁定,以为 它不是内核对象,如果要 在进程间维护线程同步,可以使用时间 内核对象。


二.互锁函数 这个比较简单直接用函数就行

 LONG InterlockerdIncrement( LONG volatile* Addend)    指向要 递增的变量

LONG InterlockerdDecrement( LONG  volatile *)   指向要递减的变量


  三.事件内核对象

 它也有守信和未受信状态,编程人员可以使用WaitFroSingleObject函数等待其变为守信状态,主要是因为一些函数可以使事件对象在这两种状态之间变化

事件对象主要成员:

nUsageCount:使用计数控制事件内核对象的销毁

bManualResert:指定在等待事件内核对象上的函数返回之后 windows是否重置这个对象为未受信状态。

bSignaled:表示当前事件是否为受信状态.

注意事项:

一种人工重置的事件另一种自动重置的事件

当人工重置的事件得到通知时等待该事件的所有线程变为可调度线程。

当自动重置的事件得到通知时,等待该事件的线程中只有一个线程变为可调度线程。然后就自动重置此事件对象为未受信状态。


主要工作:

当一个线程执行初始化操作,然后通知另一个线程执行剩余的操作时,事件使用得最多。事件初始化为未通知状态,然后,当该线程完成它的初始化操作后,它就将事件设置为已通知状态。这时,一直在等待该事件的另一个线程发现该事件已经得到通知,因此它就变成可调度线程。这第二个线程知道第一个线程已经完成了它的操作。

使用方法:

HANDLE CreateEvent(LPSECURITY_ATTRIBUTES , BOOL , BOOL , LPCWSTR) 安全属性、是否手动重置事件对象为未受信、创建初始化状态、对象名称

HANDLE OpenEvent(DWORD,BOOL,LPCWSTR)访问的权限、返回句柄是否可以被继承、事件对象名称.

BOOL SetEvent(HANDLE) 将事件状态 设置为受信状态

BOOL ResertEvent(HANDLE) 将事件状态设置为未受信状态

当一个事件对象为自动重置状态时候 当在这个事件 对象上等待的函数如:WaitForSingleObject返回时该事件对象自动变为未受信状态.


3.信号两 内核对象

限制访问共享数据的线程 数目


4.互斥内核对象(Mutex)

只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了 任何情况下此共享资源都不会同时被多个线程所访问。

使用函数:

HANDLE CreateMutex(LPSECURITY , BOOL LPCSTR) 安全属性指针,是否有初始拥有这,互斥对象名

HANDLE OpenMutex(DWORD , BOOL , LPCSTR) 访问标志、继承标志、互斥对象名字

BOOL ReleaseMutex(HANDLE hMutex) 线程离开资源时调用释放其拥有的互斥对象 以便给下个线程用

等带返回函数的值不再是WAIT_OBJECT_0 或者是 WAIT_OBJECT_0 - WAIT_OBJECT_Count+1 而是 WAIT_ABANDOEND_0 - WAIT_ABABDOEND_COUNT+1

注意:其他内核对象在没有得到通知时在等待函数的作用下线程将会挂起,同时失去可调度性,而使用互斥的方法却可以在等待的同时仍具有可调度性。


5.线程局部存取 (TLS)

windows为每个进程分配了一个数组该数组初始值都是为Free 当创建线程的时候为每个 线程分配void*的数组 并且每个线程只能访问自己的数组,线程访问自己的数组是根据主线程调用函数分配了一个全局索引然后线程根据这个索引调用存取函数操作自己的数组。

主要函数:

DWORD TlsAlloc(void); 返回一个TLS索引 在进程中挨个找索引如果对应的Free就返回该 索引把对应的值变为INUSE;

BOOL TlsSetValue(DWORD dwTlsIndex , LPVOID lpTlsValue) 设置对应数组中索引为 dwTlsIndex 的值为 lpIsValue

LPVOID TlsGetValue( DWORD dwTlsIndex) 获取线程中对应索引dwTlsIndex 成员的值

TlsFree(DWORD) 主函数调用参数为TlsAlloc 返回的索引 释放局部存取索引




0 0
原创粉丝点击