用户模式下的线程同步机制提供了非常好的性能,但他们也的确存在一些局限性,而且不适用于许多应用程序,例如,对Interlocked系列函数只能对一个值进行操作,它们从来不会把线程切换到等待状态。我们可以用关键段把线程切换到等待状态,但是他们只能用来对同一个进程中的线程进行同步,。此外,在使用关键段的时候我们很容易陷入死锁的情形,因为我们无法为进入关键段指定一个很长等待时间。接下来本文将对使用内核对象进行线程同步的相关知识进行总结。

1. 等待函数

  等待函数使一个线程自愿进入等待状态,直到指定的内核对象被触发为止。Windows提供了WaitForSingleObject和WaitForMultipleObjects两个等待函数。

1.1 WaitForSingleObject

  (1)函数格式

    DWORD WaitForSingleObject(

      HANDLE hObject,

      DWORD dwMilliseconds);

    :第二个参数为等待时间,单位毫秒,INFINITE被定义为0xFFFFFFFF  

  (2)示例

DWORD ret = WaitForSingleObject(hProcess, )
switch (ret)
{
case WAIT_OBJECT_0:
// Thew process terminated
break;
case WAIT_TIMEOUT:
// The process did not terminated within 5000 milliseconds
break;
case WAIT_FAILED:
// Bad call to function(invalid handle?)
break;
}

1.2 WaitForMultipleObjects

  (1)函数格式

    DWORD WaitForMultipleObjects(
       DWORD dwCount,  // 等待内核对象数量
       CONST HANDLE* phObjects, // 等待内核对象句柄集合
       BOOL bWaitAll,   // 判断是否等待所有内核对象触发
       DWORD dwMilliseconds); // 等待时间

  (2)示例

HANDLE phObjects[];
phObjects[] = hObject1;
phObjects[] = hObject1;
phObjects[] = hObject1;
DWORD ret = WaitForMultipleObjects(sizeof(phObjects)/sizeof(phObjects[]), phObjects, false, );
switch (ret)
{
case WAIT_TIMEOUT:
// None of objects became signaled within 5000 milliseconds
break;
case WAIT_FAILED:
// Bad call to function(invalid handle?)
break;
case WAIT_OBJECT_0 + ;
break;
case WAIT_OBJECT_0 + ;
break;
case WAIT_OBJECT_0 + ;
break;
}

2. 事件内核对象

2.1 成员函数

  (1)CreateEvent

    DWORD CreateEvent(
      PSECURITY_ATTRIBUTES psa,
      BOOL bManualReset, // 手动为TRUE,自动为FALSE
      BOOL bInitialState, // TRUE为触发,FALSE为未触发
      PCTSTR pszName
      );

  (2)OpenEvent

    HANDLE OpenEvent(
      DWORD dwDesiredAccess,
      BOOL bInherit,
      PCTSTR pszName)

  (3)SetEvent

     BOOL SetEvent(Handle hEvent)

  (4)ResetEvent

     BOOL ResetEvent(HANDLE hEvent)

2.2 重点说明

  (1)事件的触发表示一个操作已经完成,有两种类型的事件对象:手动重置事件和自动重置事件。当一个手动重置事件被触发的时候,正在等待该事件的所有线程都变成可调度状态。而当一个自动重置事件被触发的时候,只有一个正在等待该事件的线程会变成可调度状态。

  (2)其他进程中的线程访问事件对象的方法:CreateEvent、继承、DuplicateHandle或OpenEvent

  (3)对自动重置对象来说,通常不需要调用ResetEvent,这是因为系统会自动将事件重置,相反Microsoft并没有为手动重置对象定义一个等待成功所引起的副作用。

4. 可等待的计时器内核对象

5. 信号量内核对象

6. 互斥量内核对象

  互斥量(mutex)内核对象用来确保一个线程独占对一个资源的访问,互斥量对象包含一个使用计数、线程ID以及一个递归计数。

6.1 成员函数

  (1)CreateMutex

    HANDLE CreateMutex(
        PSECURITY_ATTRIBUTES psa,
        BOOL bInitialOwner, // FALSE表示不为任何线程占用
        PCTSTR pszName );

  (2)OpenMutex

      HANDLE OpenMutex(
         DWORD dwDesiredAccess,
         BOOL bInHeritHandle,
         PCTSTR pszName);

  (3)ReleaseMutex

      BOOL ReleaseMutex(HANDLE hMutex);

6.2 循环数组实现线程安全的消息队列

#include "stdio.h"
#include <Windows.h>
#include <iostream>
using namespace std;
// 数组实现循环消息队列
#define ARRAY_SIZE 8 template<typename T>
class CircleQueue
{
public:
CircleQueue();
~CircleQueue(); void PushMsg(T msg);
T PopMsg(); bool IsFull();
bool IsEmpty();
int GetLength(); void PrintCircleQueue(); private:
T *m_pArray;
int m_nArraySize;
int m_nHead;
int m_nTail;
HANDLE m_hMutex;
}; template<typename T>
CircleQueue<T>::CircleQueue():m_nHead(),m_nTail(),m_nArraySize(ARRAY_SIZE)
{
m_hMutex = CreateMutex(NULL, false, NULL);
m_pArray = new T[m_nArraySize];
} template<typename T>
CircleQueue<T>::~CircleQueue()
{
delete[] m_pArray;
m_pArray = NULL;
CloseHandle(m_hMutex);
} template<typename T>
int CircleQueue<T>::GetLength()
{
return (m_nTail-m_nHead+m_nArraySize)%m_nArraySize;
} template<typename T>
bool CircleQueue<T>::IsEmpty()
{
if (m_nTail == m_nHead)
{
return true;
}
return false;
} template<typename T>
bool CircleQueue<T>::IsFull()
{
if ((m_nTail + ) % m_nArraySize == m_nHead)
{
return true;
} return false;
} template<typename T>
T CircleQueue<T>::PopMsg()
{
T msg = static_cast<T>(NULL);
if (!IsEmpty())
{
DWORD nRet = WaitForSingleObject(m_hMutex, );
switch (nRet)
{
case WAIT_OBJECT_0:
{
msg = m_pArray[m_nHead];
cout << "从消息队列取出消息:" << msg << endl;
m_nHead = (m_nHead+) % m_nArraySize;
}
break;
case WAIT_TIMEOUT:
{
cout << "Wait TimeOut!" << endl;
}
break;
case WAIT_FAILED:
{
cout << "Wait FAILED" << endl;
}
break;
}
ReleaseMutex(m_hMutex);
}
else
{
cout << "消息队列为空!" << endl;
}
return msg;
} template<typename T>
void CircleQueue<T>::PushMsg( T msg )
{
if (!IsFull())
{
DWORD nRet = WaitForSingleObject(m_hMutex, );
switch (nRet)
{
case WAIT_OBJECT_0:
{
m_pArray[m_nTail] = msg;
cout << "添加消息到消息队列:" << msg << endl;
m_nTail = (m_nTail+) % m_nArraySize;
}
break;
case WAIT_TIMEOUT:
{
cout << "Wait TimeOut!" << endl;
}
break;
case WAIT_FAILED:
{
cout << "Wait FAILED" << endl;
}
break;
}
ReleaseMutex(m_hMutex);
}
else
{
cout << "消息队列已满,请等待..."<<endl;
}
} template<typename T>
void CircleQueue<T>::PrintCircleQueue()
{
int nStart = m_nHead;
int nEnd = m_nTail;
while(nStart!= nEnd)
{
cout << m_pArray[nStart];
nStart = (nStart+) % m_nArraySize;
}
cout << endl;
}
int main()
{
CircleQueue<int> *pQueue1 = new CircleQueue<int>;
CircleQueue<char *> *pQueue2 = new CircleQueue<char *>;
cout << "消息队列1:" << endl;
pQueue1->PushMsg();
pQueue1->PushMsg();
pQueue1->PushMsg();
pQueue1->PushMsg();
pQueue1->PopMsg();
pQueue1->PushMsg();
pQueue1->PushMsg();
pQueue1->PopMsg();
pQueue1->PushMsg();
pQueue1->PopMsg();
pQueue1->PushMsg();
pQueue1->PrintCircleQueue(); cout << "消息队列2:" << endl;
pQueue2->PushMsg("hello");
pQueue2->PushMsg("world");
pQueue2->PushMsg("I");
pQueue2->PushMsg("am");
pQueue2->PushMsg("coming");
pQueue2->PopMsg();
pQueue2->PrintCircleQueue();
return ;
}

7. 线程同步对象速查表

C++之内核对象进行线程同步的更多相关文章

  1. windows核心编程---第八章 使用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  2. Windows核心编程:第9章 用内核对象进行线程同步

    Github https://github.com/gongluck/Windows-Core-Program.git //第9章 用内核对象进行线程同步.cpp: 定义应用程序的入口点. // #i ...

  3. 《Windows核心编程系列》八谈谈用内核对象进行线程同步

    使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...

  4. 第9章 用内核对象进行线程同步(4)_死锁(DeadLock)及其他

    9.7 线程同步对象速查表 对象 何时处于未触发状态 何时处于触发状态 成功等待的副作用 进程 进程仍在运行的时候 进程终止的时(ExitProcess.TerminateProcess) 没有 线程 ...

  5. 操作系统中的进程同步与Window中利用内核对象进行线程同步的关系

    操作系统中为了解决进程间同步问题提出了用信号量机制,信号量可分为四种类型分别是互斥型信号量,记录型信号量,AND型信号量,信号量集. 互斥型信号量 互斥型信号量是资源数量为1的特殊的记录型信号量.表示 ...

  6. 第9章 用内核对象进行线程同步(3)_信号量(semaphore)、互斥对象(mutex)

    9.5 信号量内核对象(Semaphore) (1)信号量的组成 ①计数器:该内核对象被使用的次数 ②最大资源数量:标识信号量可以控制的最大资源数量(带符号的32位) ③当前资源数量:标识当前可用资源 ...

  7. 第9章 用内核对象进行线程同步(2)_可等待计时器(WaitableTimer)

    9.4 可等待的计时器内核对象——某个指定的时间或每隔一段时间触发一次 (1)创建可等待计时器:CreateWaitableTimer(使用时应把常量_WIN32_WINNT定义为0x0400) 参数 ...

  8. 第9章 用内核对象进行线程同步(1)_事件对象(Event)

    9.1 等待函数 (1)WaitForSingleObject(hObject,dwMilliseonds); ①dwMilliseconds为INFINITE时表示无限等待 ②dwMilliseco ...

  9. Windows核心编程学习九:利用内核对象进行线程同步

    注:源码为学习<Windows核心编程>的一些尝试,非原创.若能有助于一二访客,幸甚. 1.程序框架 #include "Queue.h" #include <t ...

随机推荐

  1. 【Java】仿真qq尝试:用户注册(二)

    参考: 1.corejavaI:使用解耦的try/catch与try/finally 2.Java中try catch finally语句中含有return语句的执行情况(总结版):http://bl ...

  2. 如何防止通过URL地址栏直接访问页面

    如何防止通过URL地址栏直接访问页面 一.解决方案 1,将所有页面放在WEB-INF目录下 WEB-INF是Java的web应用安全目录,只对服务端开放,对客户端是不可见的.所以我们可以把除首页(in ...

  3. Go语言学习之常量(The way to go)

    生命不止,继续go go go . 上一篇博客<Go语言学习之变量(The way to go)介绍了go中的变量,今天就介绍常量. const关键字 跟c++中一样,go中同样具有const关 ...

  4. 在 CentOS 7.0 上安装配置 Ceph 存储

    来自: https://linux.cn/article-6624-1.html Ceph 是一个将数据存储在单一分布式计算机集群上的开源软件平台.当你计划构建一个云时,你首先需要决定如何实现你的存储 ...

  5. php数组元素去空,测试奇数偶数

    <?php//返回奇数 function test_odd($var) { return($var & 1); } $a1=array("a","b&quo ...

  6. gcm 被微信弃用的原因

    作者:feng xixi链接:https://www.zhihu.com/question/21514839/answer/18496706来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商 ...

  7. Git fetch和git pull的区别, 解决Git报错:error: You have not concluded your merge (MERGE_HEAD exists).

    Git fetch和git pull的区别, 解决Git报错:error: You have not concluded your merge (MERGE_HEAD exists). Git fet ...

  8. cors实现跨域(.net和jquery)

    本文引用自:http://blog.csdn.net/xuwei_xuwei/article/details/29845865 客户端 一个jquery cors请求例子: $.ajax({     ...

  9. mysql 修改编码格式

    下载了mysql的客户端,一般其默认的编码格式是gbk,为了方便后续使用,想要将其编码格式改为utf8. 这时候的方法是: 1.进入mysql的安装目录,找到my.ini文件. 2.以txt文件的格式 ...

  10. Ubuntu 下 安装 网易云音乐

    先去网易云音乐官网下载Linux下版本的包. 默认下载到  “下载”   路径下 cd 到下载的包目录 通过使用   sudo dpkg -i netease-cloud-music_1.1.0_am ...