1.  互斥量,Mutex

#include <Windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Thread1(LPVOID lpParmeter);
DWORD WINAPI Thread2(LPVOID lpParmeter);
static HANDLE g_hMutex = INVALID_HANDLE_VALUE;
static int g_iCnt = ;
int main()
{
HANDLE hThread1 = INVALID_HANDLE_VALUE;
HANDLE hThread2 = INVALID_HANDLE_VALUE;
g_hMutex = CreateMutex(NULL, FALSE, "Mutex");
// 第二个参数:创建者是否拥有所有权,FALSE为没有所有权,
// 遇到第一个WaitForSingleObject的时候就把所有权给它,
// 所以Thread1里面的WaitForSingleObject(g_hMutex, INFINITE)能够继续执行
if (!g_hMutex)
{
cout << "Failed to CreateMutex !" << endl;
return ;
}
hThread1 = CreateThread(NULL, , Thread1, NULL, , NULL);
hThread2 = CreateThread(NULL, , Thread2, NULL, , NULL);
Sleep(); // 让2个线程有足够的时间执行完操作。
CloseHandle(hThread1);
CloseHandle(hThread2);
system("PAUSE");
return ;
}
DWORD WINAPI Thread1(LPVOID lpParmeter)
{
while (true)
{
// 请求事件对象
WaitForSingleObject(g_hMutex, INFINITE); // INFINITE: 长时间等待,差不多50天左右吧!
if (g_iCnt > )
{
Sleep();
cout << "Thread1:" << g_iCnt-- << endl;
ReleaseMutex(g_hMutex); // 释放资源
}
else
{
ReleaseMutex(g_hMutex);
break;
}
}
return ;
}
DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
{
while (true)
{
// 请求事件对象
WaitForSingleObject(g_hMutex,INFINITE);
if (g_iCnt > )
{
Sleep();
cout << "thread2:" << g_iCnt-- << endl;
ReleaseMutex(g_hMutex);
}
else
{
ReleaseMutex(g_hMutex);
break;
}
}
return ;
}

几个注意的地方:

(1)互斥量为内核对象,能够与其他线程或特殊事件取得同步;

(2)速度比临界区要慢;

(3)互斥量对象与所有其它内核对象的不同之处在于它是被线程所拥有的,互斥量对象除了记录当前信号状态外,还要记住此时那个线程拥有它。

(4)这个常来被运用于限制程序启动次数!

2.事件 Event

#include <Windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Thread1(LPVOID lpParmeter);
DWORD WINAPI Thread2(LPVOID lpParmeter);
static HANDLE g_hEvent = INVALID_HANDLE_VALUE;
static int g_iCnt = ;
int main()
{
HANDLE hThread1 = INVALID_HANDLE_VALUE;
HANDLE hThread2 = INVALID_HANDLE_VALUE;
g_hEvent = CreateEvent(NULL, false, false, "Event");
if (!g_hEvent)
{
cout << "Failed to CreateEvent !" << endl;
return ;
}
/*HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // SECURITY_ATTRIBUTES结构指针,可为NULL
BOOL bManualReset, // 手动/自动
  // TRUE: 在WaitForSingleObject后必须手动调用ResetEvent清除信号
  // FALSE:在WaitForSingleObject后,系统自动清除事件信号
BOOL bInitialState, // 初始状态
LPCTSTR lpName // 事件的名称
);*/
hThread1 = CreateThread(NULL, , Thread1, NULL, , NULL);
hThread2 = CreateThread(NULL, , Thread2, NULL, , NULL);
SetEvent(g_hEvent);
Sleep(); // 让2个线程有足够的时间执行完操作。
CloseHandle(hThread1);
CloseHandle(hThread2);
system("PAUSE");
return ;
}
DWORD WINAPI Thread1(LPVOID lpParmeter)
{
while (true)
{
// 请求事件对象
WaitForSingleObject(g_hEvent, INFINITE); // INFINITE: 长时间等待,差不多50天左右吧!
if (g_iCnt > )
{
Sleep();
cout << "Thread1:" << g_iCnt-- << endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return ;
}
DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
{
while (true)
{
// 请求事件对象
WaitForSingleObject(g_hEvent,INFINITE);
if (g_iCnt > )
{
Sleep();
cout << "thread2:" << g_iCnt-- << endl;
SetEvent(g_hEvent);
}
else
{
SetEvent(g_hEvent);
break;
}
}
return ;
}

几个注意的地方:

(1).和Mutex使用差不多,只有细微的差别;

(2).可以使用SetEvent或ResetEvent改变其状态;

(3).在应用程序中任意一处没有正确的按照规则调用SetEvent或ResetEvent,将达不到同步或互斥的目的;

(4).一般来说,都是利用Event来进行同步,而不是我们这里的让它来达到互斥;

(5).Event处于无信号状态时,相关线程或进程退出,系统并不会尝试将其置为有信号状态;

3.临界区 CRITICAL_SECTION

#include <Windows.h>
#include <iostream>
using namespace std;
DWORD WINAPI Thread1(LPVOID lpParmeter);
DWORD WINAPI Thread2(LPVOID lpParmeter);
CRITICAL_SECTION g_CriticalSection; // 定义
static int g_iCnt = ;
int main()
{
HANDLE hThread1 = INVALID_HANDLE_VALUE;
HANDLE hThread2 = INVALID_HANDLE_VALUE;
InitializeCriticalSection(&g_CriticalSection); // 初始化
hThread1 = CreateThread(NULL, , Thread1, NULL, , NULL);
hThread2 = CreateThread(NULL, , Thread2, NULL, , NULL);
Sleep(); // 让2个线程有足够的时间执行完操作。
CloseHandle(hThread1);
CloseHandle(hThread2);
DeleteCriticalSection(&g_CriticalSection); // 删除
system("PAUSE");
return ;
}
DWORD WINAPI Thread1(LPVOID lpParmeter)
{
while (true)
{
EnterCriticalSection(&g_CriticalSection); // 进入临界区,获得所有权,其他线程就等待
if (g_iCnt > )
{
Sleep();
cout << "Thread1:" << g_iCnt-- << endl;
LeaveCriticalSection(&g_CriticalSection); // 离开临界区,释放所有权
}
else
{
LeaveCriticalSection(&g_CriticalSection);
break;
}
}
return ;
}
DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
{
while (true)
{
EnterCriticalSection(&g_CriticalSection);
if (g_iCnt > )
{
Sleep();
cout << "thread2:" << g_iCnt-- << endl;
LeaveCriticalSection(&g_CriticalSection);
}
else
{
LeaveCriticalSection(&g_CriticalSection);
break;
}
}
return ;
}

几个注意的地方:

(1).比Mutex速度快;

(2).临界区在线程内的分配必须是全局的;

(3). 临界区一次只允许一个线程访问;

4.信号量Semaphore

首先说说那些关于信号量那些不得不让人伤心的事情,因为笔者大学不好学习,非常调皮,而信号量又是老师最讨论及考试的话题之一,所以我觉得这个东西非常扯淡,非常影响情绪,于是放在最后。------以上是为题外话。

为什么大学老师总是喜欢信号量呢?

因为这是一个生产者-消费者模型,并且很多计算机问题都可以看做是生产者-消费者的问题,是同步最易理解的模型。

关于理论上的知识,我就不说了,书里面很多的。

还有我不是很想实现生产者-消费者的模型,就用其他例子代替了。这个有点不负责任。

#include <Windows.h>
#include <iostream>
#include <vector>
using namespace std;
DWORD WINAPI Thread1(LPVOID lpParmeter);
DWORD WINAPI Thread2(LPVOID lpParmeter);
static HANDLE g_hSemaphore = INVALID_HANDLE_VALUE;; // 定义
static int g_iCnt = ;
int main()
{
HANDLE hThread1 = INVALID_HANDLE_VALUE;
HANDLE hThread2 = INVALID_HANDLE_VALUE;
// HANDLE CreateSemaphore (
// PSECURITY_ATTRIBUTE psa,
// LONG lInitialCount, //开始时可供使用的资源数
// LONG lMaximumCount, //最大资源数
// PCTSTR pszName);
g_hSemaphore = CreateSemaphore(NULL, , , "Semaphore");
// 初始化有1个信号量。
if (g_hSemaphore == INVALID_HANDLE_VALUE)
{
cout << "Failed to Create Semaphore!" << endl;
return ;
}
hThread1 = CreateThread(NULL, , Thread1, NULL, , NULL);
hThread2 = CreateThread(NULL, , Thread2, NULL, , NULL);
Sleep(); // 让2个线程有足够的时间执行完操作。
CloseHandle(hThread1);
CloseHandle(hThread2);
system("PAUSE");
return ;
}
DWORD WINAPI Thread1(LPVOID lpParmeter)
{
while (true)
{
WaitForSingleObject(g_hSemaphore, INFINITE); // 释放一个信号量
if (g_iCnt > )
{
Sleep();
cout << "Thread1:" << g_iCnt-- << endl;
ReleaseSemaphore(g_hSemaphore, , NULL); // 增加一个信号量
}
else
{
break;
}
}
return ;
}
DWORD WINAPI Thread2(LPVOID lpParameter)//thread data
{
while (true)
{
WaitForSingleObject(g_hSemaphore, INFINITE);
if (g_iCnt > )
{
Sleep();
cout << "thread2:" << g_iCnt-- << endl;
ReleaseSemaphore(g_hSemaphore, , NULL);
}
else
{
break;
}
}
return ;
}

几个注意的地方:

信号量内核对象对线程的同步方式与前面几种不同,它允许多个线程在同一时刻访问某一资源,但是需要限制同一时刻访问此资源的最大线程数目。

总结: 线程规模 = CPU 数 * 2 + 1

代码通过VS2005编译,运行成功,如有什么疑问,请各位看官大方赐教。

原文转自 http://blog.csdn.net/ccing/article/details/6215998

Windows下C++多线程同步与互斥简单运用(转)的更多相关文章

  1. Windows下C++多线程同步与互斥简单运用

    1.  互斥量,Mutex #include <Windows.h> #include <iostream> using namespace std; DWORD WINAPI ...

  2. 使用cwRsync实现windows下文件定时同步【转】

    1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...

  3. 使用cwRsync实现windows下文件定时同步

    1.参考文献: 使用cwRsync实现windows下文件定时同步(备份) 文件同步工具CwRsync的使用方法及常用命令详解 2.背景: 当前的SCADA架构中,有1台Server,5台FE,还有1 ...

  4. C#Stimulator项目>>>C/C++ DLL的生成和调用,Windows下的多线程

    Windows下的多线程 http://blog.csdn.net/ganpengjin1/article/category/2541791 使用C/C++建立DLL,环境VS2013 新建Win32 ...

  5. Windows下安装Redis服务、搭建简单Redis主从复制

    Redis拥有非常强大的主从复制功能,而且还支持一个master可以拥有多个slave,而一个slave又可以拥有多个slave,从而形成强大的多级服务器集群架构.目前在同一台window下安装三个r ...

  6. Windows 下针对python脚本做一个简单的进程保护

    前提: 大家运行的脚本程序经常会碰到系统异常关闭.或被其他用户错杀的情况.这样就需要一个进程保护的工具. 本文结合windows 的计划任务,实现一个简单的进程保护的功能. 利用py2exe生产 ex ...

  7. Windows下的多线程

    Windows下的进程和Linux下的进程是不一样的,它比较懒惰,从来不执行任何东西,它只是为线程提供执行环境,然后由线程负责执行包含在进程的地址空间中的代码.当创建一个进程的时候,操作系统会自动创建 ...

  8. windows 下的 Rsync 同步

    整理一下 windows 下的 rsync 文件同步. Rsync下载地址: 链接:https://pan.baidu.com/s/1nL0Ee_u76ytWKUFMeiKDIw 提取码:52in 一 ...

  9. Windows下PHP多线程扩展pthreads的安装

    pthreads扩展安装步骤 1.查看phpinfo() 获取PHP版本号及位数(x86表示32位,x64表示64位).编译器版本.PHP配置文件加载所在位置等.如下图所示: 2.pthreads扩展 ...

随机推荐

  1. 在Linux下搜索文件

    在Linux下搜索文件============================= 1,which 查找可执行文件的绝对路径 [root@aminglinux ~]# which cat /bin/ca ...

  2. nginx安装php环境

    1.php下载地址 https://secure.php.net/downloads.php(此次安装版本为7.0.33) 2.安装依赖的包 yum -y install libxml2 yum -y ...

  3. Nginx 如何处理一个请求

    基于名字的虚拟主机 Nginx首先选定由哪一个虚拟主机来处理请求.让我们从一个简单的配置(其中全部3个虚拟主机都在端口*:80上监听)开始: server { listen 80; server_na ...

  4. JZOJ 4738. 神在夏至祭降下了神谕 DP + 线段树优化

    4738. 神在夏至祭降下了神谕 Time Limits: 1000 ms  Memory Limits: 262144 KB  Detailed Limits   Goto ProblemSet D ...

  5. Spring核心技术(十四)——ApplicationContext的额外功能

    在前文的介绍中我们知道,org.springframework.beans.factory包提供了一些基本的功能来管理和控制Bean,甚至通过编程的方式来实现.org.springframework. ...

  6. TCP/IP网络编程之基于TCP的服务端/客户端(二)

    回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...

  7. 使用charles进行https抓包

    一.charles电脑端设置 1.在Charles的菜单栏上选择"Proxy"->"Proxy Settings",填入代理端口8888(这个端口不一定填 ...

  8. [转]jQuery DOM Ready

    一直以来,各种JS最佳实践都会告诉我们,将JS放在HTML的最后,即</body>之前,理由就是:JS会阻塞下载,而且,在JS中很有可能有对DOM的操作,放在HTML的最后,可以尽可能的保 ...

  9. MySQL5.7(三)数据表操作

    概念在数据库中,数据表是数据库中最重要.最基本的操作对象,是数据存储的基本单位.数据表被定义为列的集合,数据在表中是按照行和列的格式来存储的.每一行代表一条唯一的记录,每一列代表记录中的一个域.1.创 ...

  10. Python 拓展之推导式

    写在之前 推导式是从一个或多个迭代器快速简洁的创建数据结构的一种办法,它可以将循环和条件判断结合,从而可以避免语法冗长的代码. 列表推导式 我在之前的文章中(零基础学习 Python 之 for 循环 ...