首页 > 编程语言 > 详细

学习:线程互斥

时间:2020-02-01 20:33:34      阅读:63      评论:0      收藏:0      [点我收藏+]

线程安全问题: 当多个线程对同一个全局变量进行操作,并且进行写的操作的时候所引发的问题

存在线程安全问题的代码:

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

int Tickets = 10;
DWORD WINAPI  MyThreadFun_1(LPVOID pParameter) {
    while (Tickets > 0){
        printf("当前票还剩余%d张 Thread-1\n", Tickets);
        Tickets--;
        printf("卖出一张 还剩%d张\n", Tickets);
    }
    return 0;
}

DWORD WINAPI  MyThreadFun_2(LPVOID pParameter) {
    while (Tickets > 0) {
        printf("当前票还剩余%d张 Thread-2 \n", Tickets);
        Tickets--;
        printf("卖出一张 还剩%d张\n", Tickets);
    }
    return 0;
}

int main() {
    HANDLE hThreadArr[2];
    hThreadArr[0] = CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_1,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );
    hThreadArr[1] = CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_2,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );
    // 当线程执行完毕之后,恢复阻塞  ,该函数具有局限性 只能等待单个线程执行完毕的情况
    WaitForMultipleObjects(2, hThreadArr,true, INFINITE);
    // 线程被清理的两个必要条件:1、线程内核对象的计数器为0    2、线程的执行代码执行完毕 ,这里的话只有线程中执行完才会进行CloseHandle
    CloseHandle(hThreadArr[0]); 
    CloseHandle(hThreadArr[1]); 
    getchar();
    return 0;
}

技术分享图片


临界资源: 临界资源是一次仅有一个线程使用的资源

临界区: 访问临界资源的那段程序称为临界区

解决方法:

第一种实现方式:线程锁

CRITICAL_SECTION 线程锁结构体
InitializeCriticalSection 初始化线程锁结构体
EnterCriticalSection 固定锁
LeaveCriticalSection 释放锁

实现代码如下:

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

int Tickets = 10;

CRITICAL_SECTION myLock;


DWORD WINAPI  MyThreadFun_1(LPVOID pParameter) {
    while (true){
        EnterCriticalSection(&myLock);
        if (Tickets == 0) {
            break;
        }
        printf("当前票还剩余%d张 Thread-1\n", Tickets);
        Tickets--;
        printf("卖出一张 还剩%d张\n", Tickets);
        LeaveCriticalSection(&myLock);
    }
    return 0;
}


int main() {
    InitializeCriticalSection(&myLock);

    HANDLE hThreadArr[2];
    hThreadArr[0] = CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_1,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );

    hThreadArr[1] = CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_1,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );


    // 当线程执行完毕之后,恢复阻塞  ,该函数具有局限性 只能等待单个线程执行完毕的情况
    WaitForMultipleObjects(2, hThreadArr,true, INFINITE);


    // 线程被清理的两个必要条件:1、线程内核对象的计数器为0    2、线程的执行代码执行完毕 ,这里的话只有线程中执行完才会进行CloseHandle
    CloseHandle(hThreadArr[0]); 
    CloseHandle(hThreadArr[1]); 
    getchar();
    return 0;
}

第二种实现方式:互斥体

互斥体利用的是Windows互斥对象机制。 只有拥有互斥对象的线程才有访问公共资源的权限,因为互斥对象只有一个,所以能保证公共资源不会同时被多个线程访问,在线程同步与保证程序单体运行上都有相当大的用处。

特点:互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。

多进程实现的线程互斥

#include<Windows.h>
#include<stdio.h>

DWORD WINAPI  MyThreadFun(LPVOID pParameter) {
    for (int i = 100; i > 0; i--) {
        printf("%d---MyThreadFun\n", i);
        Sleep(1000);
    }
    return 0;
}

int main() {
    HANDLE mutex;

    mutex = CreateMutex(NULL, false, "MyMutex"); //创建互斥体,名称为MyMutex

    WaitForSingleObject(mutex, INFINITE); //等待获得互斥体

    for (int i = 0; i < 10; i++) {  //进行
        printf("A进程----%d \n", i);
        Sleep(1000);
    }

    ReleaseMutex(mutex);//释放互斥体
    getchar();
    return 0;

}

技术分享图片

单进程线程互斥:

#include<Windows.h>
#include<stdio.h>

HANDLE mutex;
int money = 100;

DWORD WINAPI  MyThreadFun_1(LPVOID pParameter) {
    while (money > 0){
        WaitForSingleObject(mutex, INFINITE); //等待获取互斥对象
        if (money == 0) {
            break;
        }
        money--;
        printf("%d  Thread-1\n", money);
        Sleep(50);
        ReleaseMutex(mutex);//释放互斥体
    }
    return 0;
}

DWORD WINAPI  MyThreadFun_2(LPVOID pParameter) {
    while (money > 0) {
        WaitForSingleObject(mutex, INFINITE); //等待获取互斥对象
        if (money == 0) {
            break;
        }
        money--;
        printf("%d  Thread-2\n", money);
        Sleep(50);
        ReleaseMutex(mutex);//释放互斥体
    }
    return 0;
}

int main() {
    HANDLE aThread[2];
    mutex = CreateMutex(NULL, false, "MyMutex"); //创建互斥体,名称为MyMutex
    aThread[0]= CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_1,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );
    aThread[1] = CreateThread(
        NULL,  //获取默认的安全描述符,当前用户的令牌权限 
        0,  //使用可执行文件的默认大小
        MyThreadFun_2,  // 创建线程调用的函数
        NULL,  // 传递函数中的参数
        0, //线程在创建后立即运行 
        NULL // 不返回线程标识符
    );
    getchar();

    CloseHandle(aThread[0]);
    CloseHandle(aThread[1]);

    return 0;

}

线程锁与互斥体的区别:

1、线程锁只能用于单个进程内部的线程控制,互斥体能用于单个进程,也可以多个进程
2、互斥体可以设定等待超时,但线程锁不能
3、线程意外终结时,Mutex可以避免无限等待,体现的地方比如意外exit了,而用互斥体实现线程同步,另一个进程中互斥体的句柄进行的线程还是会继续下去,不会一直进行等待
4、Mutex效率没有线程锁高

学习:线程互斥

原文:https://www.cnblogs.com/zpchcbd/p/12249758.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!