《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)原子访问的原理 ①原子访问:指的是一线程在访问某个资源的同时,能够保证没有其他线程会在同一时刻访问该资源. ...
随机推荐
- IEEEXtreme 极限编程大赛题解
这是 meelo 原创的 IEEEXtreme极限编程大赛题解 IEEEXtreme全球极限编程挑战赛,是由IEEE主办,IEEE学生分会组织承办.IEEE会员参与指导和监督的.IEEE学生会员以团队 ...
- GUC-11 线程池
import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java ...
- 丑数(UVa136)
题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=835&a ...
- scrapy-redis 更改队列和分布式爬虫
这里分享两个技巧 1.scrapy-redis分布式爬虫 我们知道scrapy-redis的工作原理,就是把原来scrapy自带的queue队列用redis数据库替换,队列都在redis数据库里面了, ...
- 【BZOJ】1152: [CTSC2006]歌唱王国Singleland
题解 读错题了,是最后留下一个牛人首长歌颂他,和其他人没有关系,t就相当于数据组数 结论题,具体可看 https://www.zhihu.com/question/59895916/answer/19 ...
- Ionic实战一:Ionic仿照微信项目
github下载地址:https://github.com/Frogmarch/ionic-wechat 博客学习地址:http://www.cnblogs.com/Frogmarch/ Ionic仿 ...
- Windows下安装mysql cluster
0.mysql集群介绍 浅谈mysql集群——http://blog.csdn.net/chenxingzhen001/article/details/7708663: 官网——http://dev. ...
- softmax 杂谈
在多分类问题中,我们可以使用 softmax 函数,对输出的值归一化为概率值.下面举个例子: import sys sys.path.append("E:/zlab/") from ...
- 文件系统层级结构标准(FHS)
参考资料:FHS 简介 FHS目前发展到3.0版本,发布于2015年6月3日,由Linux基金会在负责维护.它规定了Linux的文件层级结构,使得各Linux发行版.软件开发商知道应该将哪些文件放在哪 ...
- oneDay
难受过 迷茫过 失望过 耍脾气过 开心过 伤心过 疼过 走了这么久的路: 我只想说 程序的道路上 很难走: 本来准备都放弃了: 自己逼自己了很久想明白了: 不能什么时候都想着靠外力 自己的不足就是自己 ...