WinCE应用程序开发多线程同步

本篇博文讲述WinCE平台下多线程同步的解决方案,下一篇博文讲述进程间共享的方法。

1. 功能:实现同一个进程中多个线程间的同步,避免竞争。

2. 实现:

2.1 平台:WinCE6.0 + VS2005

2.2 思路:进程间切换是程序运行的地址空间的改变;而线程间切换仅仅是执行环境的改变。显然后者效率更高。多线程同步最常用的有4种:1)互斥量、2)事件对象、3)关键代码段、4)信号量。

2.2.1 互斥量

1)创建和清除互斥量对象句柄

HANDLE hMutex;    // 全局句柄

void main()

{

    hMutex = CreateMutex(NULL,FALSE,NULL);  // 创建句柄

    ReleaseMutex(hMutex);

    …………

    CloseHandle(hMutex);    // CloseHandle(XX);作用是使内核对象计数减1。

}

CreateMutex的3个参数的解释:

第一个参数,是互斥对象的安全属性,设置NULL为默认的安全属性;

第二个参数,为TRUE表示调用者创建互斥对象,调用线程(创建互斥对象的线程)获得互斥对象的所有权;为FALSE表示调用线程不获得互斥对象的所有权。

第三个参数,表示互斥对象的名字,NULL表示匿名的互斥对象。如果名字为NULL,则互斥量只能在一个进程中使用,如果互斥量的名字是非空,则互斥量可在多个进程间访问。

2)使用互斥量

使用WaitforSingleObject()函数访问互斥量,该函数的作用是使互斥对象内部的计数器的值加1,因此,执行完这段数据处理代码后,要调用ReleaseMutex(hMutex)使互斥量内核对象减1。只有计数器的值变为0时,才能被其他线程访问这个互斥量。

仅在下面两种情况下返回:指定的对象处于有信号状态,或者超时。

代码为:

if(WaitForSingleObject(g_hMutex,INFINITE)==WAIT_OBJECT_0)

......

ReleaseMutex()   

// 当线程对共享资源访问结束时,在当前线程中调用这个函数释放对该对象的所有权,也就是让该对象处于已通知状态。然后操作系统将互斥对象的线程ID设置为0,使互斥对象设置为有信号状态。使得其他线程有机会获得对该对象的所有权,从而获得对共享资源的访问。

3)相关细节

在哪个线程使用了互斥对象,就要在哪个线程释放互斥对象。因为互斥对象的ID存储了被调用线程的ID。当存储的线程ID与释放互斥对象的线程ID不一致时,不释放互斥对象。谁拥有互斥对象,谁释放互斥对象。

如果线程结束,则线程会自动检查互斥对象的计数器的值是否为0,如果不为0,则线程会自动将互斥对象的计数器的值复位为0.

2.2.2 事件对象

1)创建和清除事件对象句柄

HANDLE g_hEvent;

void main()

{

    g_hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)

}

2)使用事件对象

if(WaitForSingleObject(g_hEvent,INFINITE)==WAIT_OBJECT_0)

......

SetEvent(g_hEvent);

// 当线程对共享资源访问结束时,应该释放该对象的所有权,也就是让该对象处于有信号状态。  

3)相关细节

线程在使用事件对象时,事件对象处于无信号状态,直到这个线程时间片到期则让出事件对象的所有权,然后使事件对象处于有信号状态,其他线程就可以使用这个事件对象了。

线程间的同步,最好采用自动重置的事件对象,并设置初始状态为无信号状态。

将信号重置设置为手动重置时,因为当事件对象变成有信号状态时,所有等待线程均可执行。而自动重置的事件对象,当事件对象变成有信号状态时,只有一个等待线程会执行。

使用事件对象时,自动重置的更深层理解:假设线程1使用WaitForSingleObject(g_hEvent,INFINITE);请求到事件对象后,操作系统会将该事件对象设置为无信号状态。为了让本程序能够正常运行,在线程对保护的代码访问完成之后应该立即调用SetEvent函数,将该事件设置为有信号状态,允许其他等待该对象的线程变成可调度状态。

2.2.3 关键代码段

关键代码段的使用方法比较简单,不过多赘述。给出用到的4个函数如下:

InitializeCriticalSection();

DeleteCriticalSection();

EnterCriticalSection();

LeaveCriticalSection();

在WinCE平台下,实现多线程同步的最简单的方式就是关键代码段。

2.2.4 信号量

1)适用范围:用于一个生产者,多个消费者的模式,这样任一时刻就不是一个线程在执行了,而是多个线程可同时执行。

2)类似于互斥量和事件对象,使用了4个函数如下:

HANDLE m_Semphore;      // 全局信号量句柄

m_Semphore = CreateSemaphore(NULL,1,1,NULL);    // 创建信号量句柄

CloseHandle(m_Semphore);                        // 在线程结束时,调用此函数关闭句柄

WaitForSingleObject();

ReleaseSemaphore();

3. 总结:

互斥量和关键代码段适用于2个线程相互切换运行的情况。而事件对象,则适用于在一个线程中通过程序产生事件作一些处理,然后让事件对象处于有信号状态,使另一个线程获取该事件对象,然后执行另外一些处理。而且事件对象用于线程同步是最灵活的。信号

量适用于一对多的情况。

 

注:转载请注明出处http://www.cnblogs.com/zaishuiyifang006 人生如棋,我愿为卒,行动虽缓,可谁见我后退一步。
原文地址:https://www.cnblogs.com/zaishuiyifang006/p/2732522.html