网络编程(47)—— windows平台下的四种线程同步技术(一)
来源:互联网 发布:smartptt对讲软件下载 编辑:程序博客网 时间:2024/06/01 16:19
一、用户模式和内核模式
Windows操作系统在运行时,存在以下两种模式:
用户模式:是运行应用程序的基本模式,不能访问硬件,且访问的内存的范围也有限制。
内核模式:是操作系统运行的基本模式,可以访问硬件,访问的内存范围无限制。
Windows的程序在运行时,往往频繁的在用户模式和内核模式之间切换。以多线程程序为例,我们所创建的线程属于操作系统,在创建线程中就无法避免从用户模式向内核模式切换,而创建完成后,又会从内核模式切换回应用模式。Windows采用这种双模式的运行方式主要是出于安全的考虑。在用户模式中,应用程序无法访问系统内核的内存,当应用程序出现错误时也就无法导致操作系统异常,最多也就是应用程序自己会发生异常。
在Windows多线程编程中,线程同步技术按照模式也可分为两种:一是用户模式的线程同步技术CRITICAL_SECTION,二是内核模式的线程同步技术事件、互斥和信号量。下面我们分别就这两种模式下不同的线程同步技术进行讨论。
二、试验代码
首先我们引入一段使用多线程的代码:
#include "stdafx.h"#include "windows.h"#include "iostream"int g_i=0;unsigned WINAPI AddThreadFunc(void* param){for (int i=0;i<1000000;i++){g_i++;}return 0;}unsigned WINAPI DevThreadFunc(void* param){for (int i=0;i<1000000;i++){g_i--;}return 0;}int _tmain(int argc, _TCHAR* argv[]){HANDLE handles[2];handles[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)AddThreadFunc,NULL,0,NULL);handles[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DevThreadFunc,NULL,0,NULL);WaitForMultipleObjects(2,handles,true,INFINITE);std::cout<<"g_i="<<g_i<<std::endl;return 0;}
代码的作用是,创建两个线程分别对全局变量g_i进行++和—操作,如果不存在同步问题最后m_i的值将会仍然是0。但是由于我们未进行同步控制,它的结果不可能是0,而且每次运行结果应该不同。
第一次:
第二次:
第三次:
在接下来的讨论中,我们将利用上述四种线程同步技术对改段代码进行同步。
三、用户级别的线程同步技术——CRITICAL_SECTION
CRITICAL_SECTION是用户模式级别的临界区对象。和其他同步技术进行线程同步的原理作用一样,它将临界区的代码上锁,等到执行完临界区代码后再进行解锁。使用它涉及四个windows的API:
void WINAPI InitializeCriticalSection( __out LPCRITICAL_SECTION lpCriticalSection);用来初始化CRITICAL_SECTION对象,接收的参数为CRITICAL_SECTION对象的指针。
void WINAPI DeleteCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection);用来销毁CRITICAL_SECTION对象,接收的参数为CRITICAL_SECTION对象的指针。
void WINAPI EnterCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection);对临界区的代码加锁,接收的参数为CRITICAL_SECTION对象的指针。
void WINAPI LeaveCriticalSection( __inout LPCRITICAL_SECTION lpCriticalSection);对临界区的代码解锁,接收的参数为CRITICAL_SECTION对象的指针。
我们在使用临界区对象时,要将它声明为全局对象,使用CRITICAL_SECTION加锁后的代码如下:
#include "stdafx.h"#include "windows.h"#include "iostream"int g_i=0;CRITICAL_SECTION sec;unsigned WINAPI AddThreadFunc(void* param){EnterCriticalSection(&sec);for (int i=0;i<1000000;i++){g_i++;}LeaveCriticalSection(&sec);return 0;}unsigned WINAPI DevThreadFunc(void* param){EnterCriticalSection(&sec);for (int i=0;i<1000000;i++){g_i--;}LeaveCriticalSection(&sec);return 0;}int _tmain(int argc, _TCHAR* argv[]){HANDLE handles[2];InitializeCriticalSection(&sec);handles[0] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)AddThreadFunc,NULL,0,NULL);handles[1] = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)DevThreadFunc,NULL,0,NULL);WaitForMultipleObjects(2,handles,true,INFINITE);std::cout<<"g_i="<<g_i<<std::endl;DeleteCriticalSection(&sec);return 0;}
运行之后,我们得到了正确的结果:
Github位置:
https://github.com/HymanLiuTS/NetDevelopment
克隆本项目:
git clone Git@github.com:HymanLiuTS/NetDevelopment.git
获取本文源代码:
git checkout NL47
0 0
- 网络编程(47)—— windows平台下的四种线程同步技术(一)
- 网络编程(48)—— windows平台下的四种线程同步技术(二)
- 网络编程(42)—— windows平台下创建线程的四种方法(一)
- 网络编程(45)—— windows平台下销毁线程的四种方法
- 网络编程(43)—— windows平台下创建线程的四种方法(二)之用户界面线程
- 网络编程(44)—— windows平台下创建线程的四种方法(三) 工作者线程和CWinThread线程类管理
- windows下网络编程(四)——MFC CSocket
- windows 核心编程(用户模式下的线程同步)
- JAVA 并发编程-传统线程同步通信技术(四)
- JAVA 并发编程-传统线程同步通信技术(四)
- JAVA 并发编程-传统线程同步通信技术(四)
- C++线程同步的四种方式(Windows)
- windows下网络编程(一)——SDK socket
- Windows线程同步—用户模式下的线程同步
- Windows核心编程:(五)用户模式下线程同步
- Windows线程同步的四种方法
- (转)多线程编程之四——线程的同步
- mysql在windows平台下线程同步的实现方式
- MFC显示图片
- 《软技能-代码之外的生存指南》-关于职业思考
- UploadDialog使用完整代码
- 利用Oracle DBMS_SCHEDULER调用shell脚本文件
- mysql的内连接、左外连接、右外连接、完全连接
- 网络编程(47)—— windows平台下的四种线程同步技术(一)
- 用echarts画有两条线(柱)的折线(柱状)图
- 复制Oracle数据库中文字符集AMERICAN_AMERICA.ZHS16GBK数据到目的库Oracle字符集AL32UTF8
- ABAP中TYPES与DATA、TYPE与LIKE 区别
- 一篇不错的v4l2入门文档 2
- Leetcode 188. Best Time to Buy and Sell Stock IV (Hard) (cpp)
- 使用eclipse制作war包方法 web项目打包到tomcat
- Slf4j-log4j12-1.6.1.jar包目录结构
- WebGL示例