windows多线程(三) 原子操作
一、分析上一篇程序的现象
我们先从上一篇文章中的最后一个程序开始分析。
#include <stdio.h>
#include <windows.h>
const unsigned int THREAD_NUM = 10;
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
printf("我是主线程, pid = %d\n", GetCurrentThreadId()); //输出主线程pid
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 创建线程
}
WaitForMultipleObjects(THREAD_NUM,hThread,true, INFINITE); //一直等待,知道所有子线程全部返回
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
int n = *(int*)p;
Sleep(1000*n); //第 n 个线程睡眠 n 秒
printf("我是, pid = %d 的子线程\n", GetCurrentThreadId()); //输出子线程pid
printf(" pid = %d 的子线程退出\n\n", GetCurrentThreadId()); //延时10s后输出
return 0;
}
看程序的输出:

按照正常情况来看应该是每一行输出两列,但是中间有一行多出了一列,看图中圈出来的地方,pid = 208 的线程输出线程pid后并没有马上退出,而是等到了最后才退出。(可能每次运行的情况不一样,这里只说明这一种情况),这是为什么的。 这里涉及到了线程调度的问题, 说明pid = 208 的线程输出线程pid后操作系统进行了线程调度,cpu资源被其它线程抢占,这个线程直到最后才又重新分配到cpu资源,重新往下执行。

二、原子操作
这里明明是要写原子操作,但是到目前为止,并没有任何地方提及什么是原子操作,不要着急,接下来就慢慢来说。那么什么是原子操作呢?一个操作如果能够不受中断地完成,我们称之为原子操作
我们来看这个程序
#include <stdio.h>
#include <windows.h>
const unsigned int THREAD_NUM = 50;
unsigned int g_Count = 0;
DWORD WINAPI ThreadFunc(LPVOID);
int main()
{
HANDLE hThread[THREAD_NUM];
for (int i = 0; i < THREAD_NUM; i++)
{
hThread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 创建线程
}
WaitForMultipleObjects(THREAD_NUM, hThread, true, INFINITE); //一直等待,直到所有子线程全部返回
printf(" 总共 %d 个线程给 g_Count 的值加一,现在 g_Count = %d\n", THREAD_NUM, g_Count);
return 0;
}
DWORD WINAPI ThreadFunc(LPVOID p)
{
Sleep(50);
g_Count++;
Sleep(50);
return 0;
}
有一个全局变量 g_Count ,每个线程给这个全局变量加一,照这么来看最后应该输出 50 ,我们看一下程序的输出(每次都可能不一样的结果)

为什么会这样呢??? 明明有 50 个线程都给 g_Count 加一了,为什么输出 46,根源在于 g_Count++; 这条语句上,这里就只有一条c++语句,按理说不应该有问题,其实不然,现在,在这里打下断点,开始调试,打开反汇编窗口(Vs编译器快捷键 Alt+8),如下图

可以看到,这一条c++语句,被分成了三条汇编语句,先是把 g_Count 的值给寄存器 eax,然后寄存器 eax 的值加一,再把 eax 的值给 g_Count ,这样就完成一次 g_Count++ 操作。出问题的原因就在于,在这几条汇编语句执行的过程中发送了线程切换,比如,A线程刚执行完 add eax,1 还没有把 eax的值给 g_Count,这时B线程开始执行,把 g_Count 原先的值又存入 eax,这就修改了 eax 中A线程计算好的值。
因此在多线程环境中对一个变量进行读写时,我们需要有一种方法能够保证对一个值的递增操作是原子操作——即这个操作不可以被打断性,一个线程在执行原子操作时,其它线程必须等待它完成之后才能开始执行该原子操作。Windows系统为我们提供了一些以Interlocked开头的函数来完成这一任务。这里只是介绍原子操作的概念,这和线程同步息息相关,但是这些以 以Interlocked 开头的函数我们基本不用,就不一一介绍了,感兴趣的可以自己去了解。
windows多线程(三) 原子操作的更多相关文章
- windows多线程编程星球(一)
以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...
- 总结windows多线程同步互斥
windows多线程同步互斥--总结 我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同 ...
- windows多线程同步互斥--总结
我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同步--临界区 windows多线程同步 ...
- Windows多线程多任务设计初步(转)
Windows多线程多任务设计初步 [前言:]当前流行的Windows操作系统,它能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程 ...
- windows多线程同步--临界区
推荐参考博客:秒杀多线程第五篇 经典线程同步 关键段CS 关于临界区的观念,一般操作系统书上面都有. 适用范围:它只能同步一个进程中的线程,不能跨进程同步.一般用它来做单个进程内的代码快同步,效率 ...
- windows多线程接口介绍和使用
一windows多线程接口: 1 创建线程 CreateThread 与 _beginthreadex都可以实现创建线程,两个函数的参数 相同, HANDLEWINAPICreateThread( L ...
- Windows多线程编程入门
标签(空格分隔): Windows multithread programming 多线程 并发 编程 背景知识 在开始学习多线程编程之前,先来学习下进程和线程 进程 进程是指具有一定独立功能的程序在 ...
- windows多线程没那么难
windows多线程没那么难 作者:vpoet mail:vpoet_sir@163.com 上一博文中我们引入了CreateThread()多线程编程一个简单的例子,事实上我说windows 多线程 ...
- Windows多线程
//简单的引出多线程是肿么回事儿....当点击下载的时候,下载内容还没结束也可以点击资源库,其实这就用了另一个线程,弹出“下载完成”对话框的时候,没有点击确定是不能点击主页面内容的,这就是用----- ...
- windows phone 三种数据共享的方式(8)
原文:windows phone 三种数据共享的方式(8) 本节实现的内容是数据共享,实现的效果描述:首先是建立两个页面,当页面MainPage通过事件导航到页面SecondPage是,我们需要将Ma ...
随机推荐
- mfc 动态分配内存
动态内存分配new 为数组动态分配内存 为多维数组分配内存 释放内存delete malloc free 动态内存分配new int * pi; pi= new int ; 为 ...
- Linux命令学习笔记1
1.Linux命令学习 2.Mkdir /data -创建文件夹 在/下创建文件夹 data 3.Cd -目录切换 列如cd / 4.Touch /data/1 ...
- 07- django组件:中间件
1.中间件的概念 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...
- Codeforces 915 C. Permute Digits (dfs)
题目链接:Permute Digits 题意: 给出了两个数字a,b(<=1e18),保证a,b都不带前缀0.用a的字符重组一个数字使这个值最大且小于b.(保证这个值存在) 题解: 这题遇到了不 ...
- cogs468 [NOI2010]超级钢琴
http://cogs.pro:8080/cogs/problem/problem.php?pid=468 emmmmmm 今天考试爆炸顺便切了这题 这题我肯定不会啦然后看一sol.. 固定一个右端点 ...
- 解决公司的垃圾wifi dhcp获取不到ip 以及配上ip也不能联网的原因
用手机连公司的wifi时,发现dhcp自动获取不到ip,然后配置了静态ip,但是还是无法联网, 然后发现鸡巴垃圾公司傻逼操她妈的逼原来是google的dns导致不能用??? 换成114.114.11 ...
- python并发编程之多进程理论知识
一 什么是进程 进程:正在进行的一个过程或者说一个任务.而负责执行任务则是cpu. 举例(单核+多道,实现多个进程的并发执行): egon在一个时间段内有很多任务要做:python备课的任务,写书的任 ...
- lastIndexOf()
方法可返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索.
- Linux之linux基础命令
一.命令分:内部命令.外部命令① 内部命令:是由 Shell解释器解释的② 外部命令:除了Shell解释器以外的命令③ 识别命令类型:type 命令字 二.命令一般组成格式: 命令字 [选项].. [ ...
- 为什么你写的用例测不出Bug来?
我们写测试用例的目的是为了能够整理思路,把要测试的地方列出来,做为知识的积淀,用例可以交给其他测试人员执行,或者是跟需求提出者进行讨论,对用例进行补充和修改.那么为啥你写的用例测不出Bug来呢,真的是 ...