《Windows核心编程》第八章——用户模式下的线程同步
下面起了两个线程,每个对一个全局变量加500次,不假思索进行回答,会认为最后这个全局变量的值会是1000,然而事实并不是这样:
#include<iostream>
#include <process.h>
#include <windows.h> using namespace std;
typedef unsigned int (_stdcall *PThreadFunc)(void*);
int g_nCount = ; unsigned int _stdcall ThreadTest1(void*)
{
for (int i = ; i < ; i++)
{
g_nCount++;
} return ;
} unsigned int _stdcall ThreadTest2(void*)
{
for (int i = ; i < ; i++)
{ g_nCount++;
}
return ;
} void main()
{
g_nCount = 0;
HANDLE h1 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest1, NULL, 0, NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, 0, ThreadTest2, NULL, 0, NULL);
HANDLE hs[2] = {h1, h2};
WaitForMultipleObjects(2, hs, TRUE, INFINITE);
CloseHandle(h1);
CloseHandle(h2);
printf("Global count:%d\n", g_nCount); getchar();
}
然而运行多次、每次结果都不同,而且,几乎不会等于1000:

造成这种现象的原因很简单,就是g_nCount在进行自增的时候没有实现原子操作,g_nCount的本质其实是:

- Interlocked函数
为了保证自增的原子性,改为使用Interlocked函数:
#include<iostream>
#include <process.h>
#include <windows.h> using namespace std;
typedef unsigned int (_stdcall *PThreadFunc)(void*);
int g_nCount = ; unsigned int _stdcall ThreadTest1(void*)
{
for (int i = ; i < ; i++)
{
//Sleep(12);
//g_nCount ++;
InterlockedIncrement((volatile unsigned long long*)&g_nCount);
} return ;
} unsigned int _stdcall ThreadTest2(void*)
{
for (int i = ; i < ; i++)
{
//Sleep(10);
//g_nCount ++;
InterlockedIncrement((volatile unsigned long long*)&g_nCount);
}
return ;
} void main()
{
g_nCount = ;
HANDLE h1 = (HANDLE)_beginthreadex(NULL, , ThreadTest1, NULL, , NULL);
HANDLE h2 = (HANDLE)_beginthreadex(NULL, , ThreadTest2, NULL, , NULL);
HANDLE hs[] = { h1, h2 };
WaitForMultipleObjects(, hs, TRUE, INFINITE);
CloseHandle(h1);
CloseHandle(h2); printf("Global count:%d\n", g_nCount);
getchar();
}
这样就保证了自增的原子性。
- 条件变量的使用
#include <iostream>
#include <windows.h>
#include <vector>
#include <process.h>
#include "Queue.h" using namespace std;
CQueue g_Queue;
SRWLOCK g_srwLock;
CONDITION_VARIABLE g_cvProduce;
CONDITION_VARIABLE g_cvConsume; int g_nCount = ;
int g_nWriterCount = ;
int g_nReaderCount = ; unsigned int _stdcall WriterThread(void* pParam)
{
g_nWriterCount++;
//printf("Enter writerthread-%d\n", g_nWriterCount);
while (TRUE)
{
Sleep();
AcquireSRWLockExclusive(&g_srwLock);
if (g_Queue.IsFull())
{
printf("Queue is full..\n");
SleepConditionVariableSRW(&g_cvProduce, &g_srwLock, INFINITE, );
}
/*else
{ }*/
g_Queue.AddElement(g_nCount);
printf("Produce element:%d\n", g_nCount);
g_nCount++;
ReleaseSRWLockExclusive(&g_srwLock);
WakeConditionVariable(&g_cvConsume);
}
return ;
} unsigned int _stdcall ReaderThread(void* pParam)
{
g_nReaderCount++;
//printf("Enter readerthread-%d\n", g_nReaderCount);
while (TRUE)
{
Sleep();
//这里使用的例子和书中的例子有所不同,书中的例子中的ReaderThread仅仅是读取队列中的内容,而这里 //会去修改队列的内容,所以不能使用AcquireSRWLockShared.
AcquireSRWLockExclusive(&g_srwLock);
if (g_Queue.IsEmpty())
{
printf("Queue is empty..\n");
SleepConditionVariableSRW(&g_cvConsume, &g_srwLock, INFINITE, );
}
/*else
{ }*/
printf("Consume element:%d\n", g_Queue.DelElement());
ReleaseSRWLockExclusive(&g_srwLock);
WakeAllConditionVariable(&g_cvProduce);//don't use wakeconditionvariable().
}
return ;
} void main()
{
InitializeSRWLock(&g_srwLock);
HANDLE hWriter1 = (HANDLE)_beginthreadex(NULL, , WriterThread, NULL, , NULL);
HANDLE hWriter2 = (HANDLE)_beginthreadex(NULL, , WriterThread, NULL, , NULL);
HANDLE hReader1 = (HANDLE)_beginthreadex(NULL, , ReaderThread, NULL, , NULL);
HANDLE hReader2 = (HANDLE)_beginthreadex(NULL, , ReaderThread, NULL, , NULL);
HANDLE hReader3 = (HANDLE)_beginthreadex(NULL, , ReaderThread, NULL, , NULL);
HANDLE hArray[] = { hWriter1, hWriter2, hReader1, hReader2, hReader3 };
WaitForMultipleObjects(, hArray, TRUE, INFINITE);
CloseHandle(hWriter1);
CloseHandle(hWriter2);
CloseHandle(hReader1);
CloseHandle(hReader2);
CloseHandle(hReader3);
getchar(); }

《Windows核心编程》第八章——用户模式下的线程同步的更多相关文章
- 【windows核心编程】 第八章 用户模式下的线程同步
Windows核心编程 第八章 用户模式下的线程同步 1. 线程之间通信发生在以下两种情况: ① 需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性 ② 一个线程需要通知其他线程 ...
- windows核心编程---第八章 使用内核对象进行线程同步
使用内核对象进行线程同步. 前面我们介绍了用户模式下线程同步的几种方式.在用户模式下进行线程同步的最大好处就是速度非常快.因此当需要使用线程同步时用户模式下的线程同步是首选. 但是用户模式下的线程同步 ...
- windows核心编程---第七章 用户模式下的线程同步
用户模式下的线程同步 系统中的线程必须访问系统资源,如堆.串口.文件.窗口以及其他资源.如果一个线程独占了对某个资源的访问,其他线程就无法完成工作.我们也必须限制线程在任何时刻都能访问任何资源.比如在 ...
- 《windows核心编程系列》七谈谈用户模式下的线程同步
用户模式下的线程同步 系统中的线程必须访问系统资源,如堆.串口.文件.窗口以及其他资源.如果一个线程独占了对某个资源的访问,其他线程就无法完成工作.我们也必须限制线程在任何时刻都能访问任何资源.比如在 ...
- Windows核心编程:第8章 用户模式下的线程同步
Github https://github.com/gongluck/Windows-Core-Program.git //第8章 用户模式下的线程同步.cpp: 定义应用程序的入口点. // #in ...
- 用户模式下的线程同步的分析(Windows核心编程)
线程同步 同一进程或者同一线程可以生成许多不同的子线程来完成规定的任务,但是多个线程同时运行的情况下可能需要对某个资源进行读写访问,比如以下这个情况:创建两个线程对同一资源进行访问,最后打印出这个资源 ...
- Windows核心编程 第八章 用户方式中线程的同步(上)
第8章 用户方式中线程的同步 当所有的线程在互相之间不需要进行通信的情况下就能够顺利地运行时, M i c r o s o f t Wi n d o w s的运行性能最好.但是,线程很少能够在所有的时 ...
- 第8章 用户模式下的线程同步(4)_条件变量(Condition Variable)
8.6 条件变量(Condition Variables)——可利用临界区或SRWLock锁来实现 8.6.1 条件变量的使用 (1)条件变量机制就是为了简化 “生产者-消费者”问题而设计的一种线程同 ...
- 第8章 用户模式下的线程同步(1)_Interlocked系列函数
8.1 原子访问:Interlocked系列函数(Interlock英文为互锁的意思) (1)原子访问的原理 ①原子访问:指的是一线程在访问某个资源的同时,能够保证没有其他线程会在同一时刻访问该资源. ...
随机推荐
- MFC+WinPcap编写一个嗅探器之五(过滤模块)
这一节主要介绍如何获设置捕获过滤,这里的过滤是指在捕获前过滤 设置捕获过滤主要是在CFilterDlg中完成,也就是对应之前创建的设置过滤规则对话框,如图: 首先要根据用户的选择来生成一个合法的过滤规 ...
- 7-15 Square Destroyer 破坏正方形 uva1603
先是处理所有的正方形 从边长为1开始 将其边存好 满边存好 然后不断扫描正方形 并且进行拆除 直到拆完或者 步数小于等于9(启发方程 因为n小于等于5 九次足以将所有的拆完) 代码实施有很多细 ...
- BeautifulSoup与Xpath解析库总结
一.BeautifulSoup解析库 1.快速开始 html_doc = """ <html><head><title>The Dor ...
- virtualenv虚拟环境安装不同版本的django
在开发Python应用程序的时候,系统安装的Python3只有一个版本:3.4.所有第三方的包都会被pip安装到Python3的site-packages目录下. 如果我们要同时开发多个应用程序,那这 ...
- JS 常用库汇总收集
本文不定期更新, 用于汇总记录一些看着 ok 的 JS 库. 库名 简介 项目地址 macy.js 仅 4 kb的 原生 流布局插件 http://macyjs.com/ Driver.js 仅 4 ...
- loj#2537. 「PKUWC2018」Minimax
题目链接 loj#2537. 「PKUWC2018」Minimax 题解 设\(f_{u,i}\)表示选取i的概率,l为u的左子节点,r为u的子节点 $f_{u,i} = f_{l,i}(p \sum ...
- loj#2721. 「NOI2018」屠龙勇士
题目链接 loj#2721. 「NOI2018」屠龙勇士 题解 首先可以列出线性方程组 方程组转化为在模p意义下的同余方程 因为不保证pp 互素,考虑扩展中国剩余定理合并 方程组是带系数的,我们要做的 ...
- bzoj 4408: [Fjoi 2016]神秘数 数学 可持久化线段树 主席树
https://www.lydsy.com/JudgeOnline/problem.php?id=4299 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1 ...
- bzoj 4092 DP
简化题意: 给定两个集合A,B,A集合有一个权值,并且对应一个B集合的子集,求A的一个子集,满足权值和最小且对应的子集的并集是B集合. 感觉像网络流,但因为每个B中的元素对应一个A中的元素就行了,是o ...
- Poj 题目分类
初期:一.基本算法: (1)枚举. (poj1753,poj2965) (2)贪心(poj1328,poj2109,poj2586) (3)递归和分治法. (4)递推. ...