线程的互斥与同步

线程的互斥与同步

互斥:

当多个线程访问同一个全局变量,或者同一个资源(比如打印机)的时候,需要进行线程间的互斥操作来保证访问的安全性。
临界区、互斥体、事件和信号量都可以实现线程互斥.但如果仅仅需要实现互斥功能,推荐前两种:

在这里插入图片描述
两者的区别:

1、临界区只能用于进程内的线程互斥,性能较好.
2、互斥体属于内核对象,可以用于进程间的线程互斥,性能较差.
3、线程在没有正常退出互斥区而意外终结时,互斥体可以复位,但临界区不行.

同步:

​ 当有多个线程同时执行时,可能需要线程按照一定的顺序执行,比如:线程A负责将要处理的数据读取到内存中,而线程B负责分析这些数据,此时,应该是线程A执行完毕再执行线程B才有意义,这个时候就需要进行线程的同步控制。

可以用于线程同步控制的对象:事件和信号量

在这里插入图片描述

两者的区别:

1、都是内核对象,使用完毕后应该关闭句柄.
2、信号量可以用于相当复杂的线程同步控制.

临界区的使用:

1、创建CRITICAL_SECTION:

CRITICAL_SECTION cs;

2、在使用前进行初始化

InitializeCriticalSection(&cs);

3、在函数中使用:

DWORD WINAPI 线程A(PVOID pvParam)
{
EnterCriticalSection(&cs);

​ //对全局遍历X的操作

​ LeaveCriticalSection(&cs);

​ return(0);
}

DWORD WINAPI 线程B(PVOID pvParam)
{
​ EnterCriticalSection(&g_cs);

//对全局遍历X的操作

​ LeaveCriticalSection(&g_cs);

​ return(0);
}

4、删除CRITICAL_SECTION

VOID DeleteCriticalSection(PCRITICAL_SECTION pcs);

当线程不再试图访问共享资源时

互斥体的使用:

HANDLE CreateMutexW(

LPSECURITY_ATTRIBUTES lpMutexAttributes,

BOOL bInitialOwner, // False:创建后,能直接使用(有信号)

​ // True: 创建后,不能直接使用(没信号),表示当前互斥体属于当前的进程

LPCWSTR lpName // 给内核互斥体命名

);

获取互斥体令牌的方式:

  1. 有信号

  2. 线程的拥有者 (即使参数为 True,A进程仍能获取互斥体,但 B进程无法获取)

// 互斥体.cpp (A进程)

int main() {

// 创建一个互斥体

HANDLE hMutex = CreateMutex(NULL, FALSE, L"XYZ");

// 获取互斥体

WaitForSingleObject(hMutex, INFINITE);

for (int i = 0; i < 10; i++) {

Sleep(1000);

printf(“A进程的X线程 %d\n”, i);

}

// 释放互斥体

ReleaseMutex(hMutex);

return 0;

}

// Test.cpp (B进程)

int main() {

HANDLE hMutex = CreateMutex(NULL, FALSE, L"XYZ");

// 这个互斥体创建失败,因为 A进程已经创建了一个同名互斥体

// 但仍会返回同名互斥体的句柄

WaitForSingleObject(hMutex, INFINITE);

for (int i = 0; i < 10; i++) {

​ Sleep(1000);

​ printf(“B进程的Y线程 %d\n”, i);

}

ReleaseMutex(hMutex);

return 0;

}

事件的使用:

1、事件对象的创建

HANDLE CreateEvent(
LPSECURITY_ATTRIBUTES lpEventAttributes, // 安全属性 NULL时为系统默认
BOOL bManualReset, // TRUE 通过调用ResetEvent将事件对象标记为未通知
BOOL bInitialState, // TRUE 已通知状态 FALSE未通知状态
LPCTSTR lpName // 对象名称 以NULL结尾的字符串
);

2、事件对象的控制

BOOL SetEvent(HANDLE hEvent); //将对象设置为已通知

3、关闭时间对象句柄

CloseHandle(); //关闭句柄

信号量的使用:

创建信号量

HANDLE CreateSemaphore(

LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

LONG lInitialCount,

LONG lMaximumCount,

LPCTSTR lpName

);

函数说明:

第一个参数表示安全控制,一般直接传入NULL。

第二个参数表示初始资源数量。0时不发送信号

第三个参数表示最大并发数量。lInitialCount<=lMaximumCount

第四个参数表示信号量的名称,传入NULL表示匿名信号量。

打开信号量

HANDLE OpenSemaphore(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

LPCTSTR lpName

);

函数说明:

第一个参数表示访问权限,对一般传入SEMAPHORE_ALL_ACCESS。详细解释可以查看MSDN文档。

第二个参数表示信号量句柄继承性,一般传入FALSE即可。

第三个参数表示名称,不同进程中的各线程可以通过名称来确保它们访问同一个信号量。

递增信号量的当前资源计数

BOOL ReleaseSemaphore(

HANDLE hSemaphore,

LONG lReleaseCount,

LPLONG lpPreviousCount

);

函数说明:

第一个参数是信号量的句柄。

第二个参数表示增加个数,必须大于0且不超过最大资源数量。

第三个参数返回当前资源数量的原始值,设为NULL表示不需要传出。

注:没有一个函数可以用来查询信标的当前资源数量的值

信号量的清理与销毁

CloseHandle()

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值