windows多线程(六) 互斥量Mutex与关键段CriticalSection比较

一、关键段CS 和 互斥量Mutex 的相同点:都有线程拥有权

关键段和互斥量都有线程拥有权,即可以被一个线程拥有。在 前面讲关键段CS的文章中有说到,关键段结构体的第四个参数保存着拥有该关键段的线程的句柄,具体如下:


typedef struct _RTL_CRITICAL_SECTION {
    PRTL_CRITICAL_SECTION_DEBUG DebugInfo;

    //
    //  The following three fields control entering and exiting the critical
    //  section for the resource
    //

    LONG LockCount;
    LONG RecursionCount;
    HANDLE OwningThread;        // from the thread‘s ClientId->UniqueThread
    HANDLE LockSemaphore;
    ULONG_PTR SpinCount;        // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
  • 第一个参数:PRTL_CRITICAL_SECTION_DEBUG DebugInfo; 调试的时候用的,先不做介绍。
  • 第二个参数:LONG LockCount; 初始化为-1,n表示有n个线程在等待。
  • 第三个参数:LONG RecursionCount; 表示该关键段的拥有线程对此资源获得关键段次数,初为0。
  • 第四个参数:HANDLE OwningThread; 即拥有该关键段的线程句柄
  • 第五个参数:HANDLE LockSemaphore; 实际上是一个自复位事件。
  • 第六个参数:ULONG_PTR SpinCount; 旋转锁的设置,用于多处理器。

现在我们来分析以下程序:


#include<iostream>
#include <windows.h>
using namespace std;

const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
DWORD WINAPI ThreadFunc(LPVOID);

int main()
{
    InitializeCriticalSection(&cs);
    HANDLE hThread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM; i++)
    {
        EnterCriticalSection(&cs);  // 进入关键段,执行这一句时主线程就获得了这个关键段的拥有权。
        hThread[i] = CreateThread(NULL, 0, ThreadFunc,0, 0, NULL);
    }
    WaitForMultipleObjects(THREAD_NUM, hThread,true,INFINITE);
    cout << THREAD_NUM << " 个线程全部返回" << endl;

    return 0;
}

DWORD WINAPI ThreadFunc(LPVOID p)
{
    LeaveCriticalSection(&cs);  // 离开关键段
    Sleep(50);
    EnterCriticalSection(&cs);  // 进入关键段
    cout<<"g_Count 的值为:"<<g_Count++<<endl;
    LeaveCriticalSection(&cs);  // 离开关键段
    Sleep(50);

    return 0;
}

如下图所示加上两个断点进行调试,正常来说程序应该是依次经过两个断点,但是调试时我们发现,程序会多次重复进入第一个断点,这是因为执行到第一个断点式时主线程就获得了这个关键段的拥有权。

同样地,Mutex也拥有线程所有权,需要了解互斥量看这里。和上面一样,我们写这样一个程序


#include <iostream>
#include <windows.h>
using namespace std;

const unsigned int THREAD_NUM = 10;
unsigned int g_Count = 0;
CRITICAL_SECTION cs;
HANDLE g_Mutex;
DWORD WINAPI ThreadFunc(LPVOID);

int main()
{
    InitializeCriticalSection(&cs);
    g_Mutex = CreateMutex(NULL, false, NULL);  //初始化互斥量为触发状态
    HANDLE hTread[THREAD_NUM];
    for (int i = 0; i < THREAD_NUM;i++)
    {
        WaitForSingleObject(g_Mutex, INFINITE);  //等待互斥量触发
        hTread[i] = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL);
    }
    WaitForMultipleObjects(THREAD_NUM, hTread, true, INFINITE);
    cout << THREAD_NUM << " 个线程全部返回" << endl;
    return 0;
}

DWORD WINAPI ThreadFunc(LPVOID p)
{
    //ReleaseMutex(g_Mutex);
    Sleep(50);
    EnterCriticalSection(&cs);  // 进入关键段
    cout << "g_Count 的值为:" << g_Count++ << endl;
    LeaveCriticalSection(&cs);  // 离开关键段
    Sleep(50);
    ReleaseMutex(g_Mutex);  //触发互斥量
    return 0;
}

同样地,我们在程序中下两个断点,同样地程序会不经过第二个断点,而重复经过第一个断点。

前面关键段和互斥量两篇文章我们说了关键段CS和互斥量Mutex不能做到线程同步,只能做到临界资源互斥访问,就是因为,他它们都有线程拥有权的原因。

二、关键段CS 和 互斥量Mutex 的不同点:由于互斥量常用于多进程之间的线程互斥,所以它比关键段还多一个很有用的特性——“遗弃”情况的处理。

看下面的程序:

程序一:


#include <stdio.h>
#include <windows.h>

const char MutexName[] = "MyMutex"; //互斥量名字

int main()
{
    HANDLE hMutex = CreateMutex(NULL, TRUE, MutexName); //创建互斥量并初始化为未触发状态
    printf("互斥量已经创建,按任意键触发\n");
    getch();
    exit(0); //在互斥量触发前退出程序。
    //ReleaseMutex(hMutex); // 触发互斥量
    printf("互斥量已经被触发\n");
    CloseHandle(hMutex);
    return 0;
}

程序二:


#include <stdio.h>
#include <windows.h>

const char MutexName[] = "MyMutex"; //互斥量名字

int main()
{
    HANDLE hMutex = OpenMutex(MUTEX_ALL_ACCESS, TRUE, MutexName); //打开互斥量

    if (NULL != hMutex)
    {
        printf("打开互斥量成功,等待互斥量被触发\n");
        DWORD mRes = WaitForSingleObject(hMutex, INFINITE); // 等待互斥量被触发
        if (WAIT_ABANDONED == mRes)  //判断互斥量是否被遗弃
        {
            printf("互斥量被遗弃。\n");
        }
        //printf("互斥量已经被触发\n");
    }
    else
    {
        printf("互斥量打开失败。\n");
    }

    CloseHandle(hMutex);
    return 0;
}

先运行,程序一,然后运行程序二,如下图所示。

此时在,程序一中按任意键,使程序一在互斥量未触发之前退出,程序二输出如下:

这篇是边学边写出来的可能有不正确的地方,欢迎指出!!!!!

原文地址:https://www.cnblogs.com/ay-a/p/9048092.html

时间: 2024-10-28 07:33:32

windows多线程(六) 互斥量Mutex与关键段CriticalSection比较的相关文章

转--- 秒杀多线程第七篇 经典线程同步 互斥量Mutex

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互斥量Mutex主要将用到四个函数.下面是这些函数

秒杀多线程第七篇 经典线程同步 互斥量Mutex

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互斥量Mutex主要将用到四个函数.下面是这些函数

(转)经典线程同步 互斥量Mutex

阅读本篇之前推荐阅读以下姊妹篇: <秒杀多线程第四篇一个经典的多线程同步问题> <秒杀多线程第五篇经典线程同步关键段CS> <秒杀多线程第六篇经典线程同步事件Event> 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用互斥量Mutex来解决这个问题. 互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互斥量Mutex主要将用到四个函数.下面是这些函数

Linux多线程--使用互斥量同步线程【转】

本文转载自:http://blog.csdn.net/ljianhui/article/details/10875883 前文再续,书接上一回,在上一篇文章:Linux多线程——使用信号量同步线程中,我们留下了一个如何使用互斥量来进行线程同步的问题,本文将会给出互斥量的详细解说,并用一个互斥量解决上一篇文章中,要使用两个信号量才能解决的只有子线程结束了对输入的处理和统计后,主线程才能继续执行的问题. 一.什么是互斥量 互斥量是另一种用于多线程中的同步访问方法,它允许程序锁住某个对象,使得每次只能

[线程同步互斥]互斥量Mutex

互斥量也是一个内核对象,它用来确保一个线程独占一个资源的访问.互斥量与关键段的行为非常相似,并且互斥量可以用于不同进程中的线程互斥访问资源.使用互斥量Mutex主要将用到四个函数.下面是这些函数的原型和使用说明. 第一个 CreateMutex 函数功能:创建互斥量(注意与事件Event的创建函数对比) 函数原型: HANDLECreateMutex( LPSECURITY_ATTRIBUTESlpMutexAttributes, BOOLbInitialOwner, LPCTSTRlpName

linux系统编程:线程同步-互斥量(mutex)

线程同步-互斥量(mutex) 线程同步 多个线程同时访问共享数据时可能会冲突,于是需要实现线程同步. 一个线程冲突的示例 #include <stdio.h> #include <unistd.h> #include <pthread.h> #define Loop 1000000 //全局资然 int counter = 0; void *fun(void *argv) { int i; for (i = 0; i < Loop; i++) { counter

多线程相关------互斥量

互斥量(Mutex) 互斥量是一个可以处于两态之一的变量:解锁和加锁.只有拥有互斥对象的线程才具有访问资源的权限.并且互斥量可以用于不同进程中的线程的互斥访问. 相关函数: CreateMutex用于创建互斥量 HANDLE WINAPI CreateMutex( _In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, _In_ BOOL bInitialOwner, _In_opt_ LPCTSTR lpName ); lpMutexAttribut

linux C 互斥量mutex 使用记录

一.互斥量 Mutex 主要包含一下几个函数: 1.int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); 初始化一个mutex,如果attr为NULL测按默认值初始化,另外还可以在定义互斥量的时候按照下面的方式初始化一个互斥量: pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 一个被lock的信号量,可以直接被恢复到初始态而不产生错误

数据共享之互斥量mutex

互斥量介绍 互斥量可以保护某些代码只能有一个线程运行这些代码.如果有个线程使用互斥量执行某些代码,其他线程访问是会被阻塞,直到这个线程执行完这些代码,其他线程才可以执行. 一个线程在访问共享数据前,给互斥量上锁,这时其他线程再给互斥量上锁会阻塞直到这个线程给互斥量解锁. 互斥量是C++中最常用的数据保护机制,但是它也不万能的.在编写代码时,合理的组织代码来避免资源竞争非常重要.使用互斥量可能会带来其他问题,比如死锁. 在C++中使用互斥量 创建互斥量使用mutex,给互斥量上锁使用函数lock(