网络编程(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
原创粉丝点击