所有同步方法

1. 线程同步

 问题:多个线程对同一个回调函数操作,导致一段代码未执行完就开始切换下一个线程,造成数据混乱。为了不造成混乱,使用了限定操作 同步

1.1 原子操作 -- 单值

Interlocked function  函数里有关原子操作

互锁函数同步对多个线程共享的变量的访问。它们的目的是防止线程在递增或检查变量时被抢占。不同进程的线程可以使用这些函数,因为它们的变量共享内存。Windows CE支持三个互锁函数

InterlockedIncrement 增加一个共享变量并检查结果值

InterlockedDecrement 递减共享变量并检查结果值

InterlockedExchange 交换指定变量的值

InterlockedTestExchange 只有当其中一个变量是特定的,才交换指定变量的值

       InterlockedExchangeAdd -- 加法操作不可打断

InterlockExchangeAdd函数向addend变量执行增量值的原子加法。该函数防止多个线程同时使用同一个变量。

1.2 关键段

使用关键段首先先要定义一个结构体变量

CRITICAL_SECTION  cs;

这是一个传出变量

  //初始化关键段

  InitializeCriticalSection(&cs);

//如果锁着,则等待,如果没有锁着,则返回, 并上锁

       EnterCriticalSection(&cs)

          在同一个线程调用,会增加引用计数,几次enter,需要对应次数的leave

 //解锁,让出所有权

       LeaveCriticalSection(&cs);

 EnterCriticalSection(&cs)和LeaveCriticalSection(&cs)必须成对使用;

 

       TryEnterCriticalSection(&cs);  有返回值

          TRUE,进入关键段,并上锁

          FALSE,其他线程在使用

       LeaveCriticalSection(&cs)

TryEnterCriticalSection和EnterCriticalSection使用方式相同 不过有一个BOOL的返回值表示是否获得所有权

       

       InitializeCriticalSection(&cs); 初始化

 

       DeleteCriticalSection(&cs);  反初始化

1.3 内核同步对象(事件, 信号灯, 互斥体)

   在多线程的情况下,有时候我们会希望等待某一线程完成了再继续做其他事情,要实现这个目的,可以使用Windows API函数WaitForSingleObject,或者WaitForMultipleObjects。这两个函数都会等待Object被标为有信号(signaled)时才返回的。

那么,信号是什么呢?首先我们可以假设这里存在一个文件和两个线程,我们规定这个文件同一时刻只能被一个线程所访问打开,那么我们的线程该如何知道这个文件现在有没有被别的线程访问呢?我们可以让线程等在一个死循环里,这个循环之一在尝试打开访问这个文件,直到能够打开为止;这样做虽然可以实现目的,但是死循环会占用大量的内存,所以windows就设置了信号量。信号量的作用简单理解就是一个标志位,在我们上述的问题中,这个文件就有一个信号量,初始时我们设信号量为FALSE,而只有当信号量为FALSE时线程才可以打开访问这个文件。那么,当第一个线程到达,信号量为FALSE,线程打开文件进行访问,并将信号量置为TRUE;在第一个线程在访问文件时,第二个线程到来,此时信号量仍未TRUE,所以第二个线程等待,这个等待的过程就是WaitForSingleObjectWaitForSingleObject在等待的过程中会进入一个非常高效的沉睡等待状态,只占用极少的CPU时间片。

       state(状态)

           signaled -- 已触发, 开锁

           no-signal -- 未触发, 关锁

       process/线程

          signaled -- 结束运行

          no-signal -- 正在运行   

       

      检测方式:

WaitForSingleObject等待的对象Event,Mutex,Semaphore,Process,Thread 

有三种返回类型:

WAIT_OBJECT_0, 表示等待的对象有信号(对线程来说,表示执行结束);

 WAIT_TIMEOUT, 表示等待指定时间内,对象一直没有信号(线程没执行完);

WAIT_ABANDONED 表示对象有信号,但还是不能执行  一般是因为未获取到锁或其他原因

      WaitForSingleObject -- 等待一个对象

DWORD WaitForSingleObject(

HANDLE hHandle, // handle to object     对象句柄 可以是信号或者进程

 DWORD dwMilliseconds // time-out interval);等待时间

INFINITE    一直等时间结束 宏的值为-1

 

          WaitForMultipleObjects  -- 等待多个对象

DWORD WaitForMultipleObjects(

DWORD nCount, // number of handles in array    个数

CONST HANDLE *lpHandles, // object-handle array 句柄数组

 BOOL bWaitAll, // wait option 等待选项

 DWORD dwMilliseconds // time-out interval);等待时间

1.4 事件(event)

事件对象就像一个开关:它只有两种状态---开和关。当一个事件处于”开”状态,我们称其为”有信号”否则称为”无信号”。可以在一个线程的执行函数中创建一个事件对象,然后观察它的状态,如果是”无信号”就让该线程睡眠,这样该线程占用的CPU时间就比较少。

 一个Event被创建以后,可以

OpenEvent()API来获得它的Handle

CloseHandle() 来关闭它,

SetEvent()或PulseEvent()来设置它使其有信号,

ResetEvent()来使其无信号,

WaitForSingleObject()或WaitForMultipleObjects()来等待其变为有信号. 

  

      CreateEvent -- 创建事件对象

HANDLECreateEvent(

LPSECURITY_ATTRIBUTESlpEventAttributes,  // 安全属性

BOOLbManualReset, // 复位方式 true表示 手工设置触发和未触发  false表示默认系统设置  一般系统直接设置为未触发状态

BOOLbInitialState, // 初始状态  true表示开始触发

LPCTSTRlpName // 对象名称 若是本进程使用不需要跨进程  跨进程配合OpenEvent使用

);

      SetEvent  -- 将事件对象设置为已触发(开锁)状态

      ResetEvent -- 将事件对象设置为未触发(关锁)状态

      OpenEvent -- 通过名字打开一个事件对象

HANDLEOpenEvent(

DWORD dwDesiredAccess,EVENT_ALL_ACCESS 指定事件对象所有可能的权限

BOOL bInheritHandle,句柄是否继承 

LPCTSTR lpName即将要打开的事件对象的名字

);

学如逆水行舟,不进则退。 博客园技术交流群 群 号:1073255314 (本群没人,刚刚建立 -_-!!! )
原文地址:https://www.cnblogs.com/Mj-NaijAm/p/13615489.html