#include <stdio.h>
#include <process.h>
#include <Windows.h>
#include <iostream>
#include <chrono>
#include <iomanip>
// 线程数量
#define THREAD_NUM 10
HANDLE* handles = new HANDLE[THREAD_NUM];
unsigned long long ticketNum = 100000;
/*
CreateMutexA(
_In_opt_ LPSECURITY_ATTRIBUTES lpMutexAttributes, 安全属性、如果此参数为 NULL,则互斥体将使用默认的安全描述符。
_In_ BOOL bInitialOwner, 如果此参数为 TRUE,则创建互斥体的线程将成为其初始所有者。这意味着该线程将拥有对同步资源的独占访问权,并且互斥体将处于未触发状态(即其他线程无法访问)。如果此参数为 FALSE,则互斥体在创建时不被任何线程拥有,并且处于触发状态(即其他线程可以调用等待函数来尝试获取它)
_In_opt_ LPCSTR lpName、这是一个指向字符串的指针,用于指定互斥体的名称。
);
*/
HANDLE hmutex = CreateMutex(NULL, FALSE, NULL);
/*
CreateEventA(
_In_opt_ LPSECURITY_ATTRIBUTES lpEventAttributes,安全属性、如果此参数为 NULL,则互斥体将使用默认的安全描述符。
_In_ BOOL bManualReset,指定事件对象是否为手动重置。如果为 `TRUE`,则需要使用 `ResetEvent` 函数来手动将事件状态重置为无信号状态。如果为 `FALSE`,则系统会自动在单个等待线程被释放后重置事件状态
_In_ BOOL bInitialState,指定事件对象的初始状态。如果为 `TRUE`,则初始状态为有信号状态;如果为 `FALSE`,则为无信号状态
_In_opt_ LPCSTR lpName,指定事件对象的名称。如果为 `NULL`,则创建一个匿名的事件对象
);
*/
HANDLE hevent = CreateEventA(NULL, FALSE, TRUE, NULL);
/*
CreateSemaphoreA(
_In_opt_ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,安全属性、如果此参数为 NULL,则互斥体将使用默认的安全描述符。
_In_ LONG lInitialCount,这个参数指定信号量的初始计数。它表示可以同时访问共享资源的线程数。
_In_ LONG lMaximumCount,这个参数指定信号量的最大计数。它表示可以访问共享资源的最大线程数。
_In_opt_ LPCSTR lpName,指定事件对象的名称。如果为 `NULL`,则创建一个匿名的事件对象
);
*/
HANDLE hsemaphore = CreateSemaphoreA(NULL, 1, 1, NULL);
// 临界区,使用临界区实现同步功能
CRITICAL_SECTION g_cs;
// 使用互斥体去卖票、总花费时间:12608ms
unsigned long WINAPI HandleMutexMethod(void* arg)
{
int* i = (int*)arg;
while (ticketNum > 0)
{
WaitForSingleObject(hmutex, INFINITE);
if (ticketNum > 0)
{
ticketNum--;
printf("%d成功卖出一张票。余票为:%lld\n", *i, ticketNum);
}
else {
ReleaseMutex(hmutex);
break;
}
ReleaseMutex(hmutex);
}
printf("%d票卖完了。余票为:%lld\n", *i, ticketNum);
delete arg;
return 0;
}
// 使用事件去卖票、总花费时间:12175ms
unsigned long WINAPI HandleEventMethod(void* arg)
{
int* i = (int*)arg;
while (ticketNum > 0)
{
WaitForSingleObject(hevent, INFINITE);
if (ticketNum > 0)
{
ticketNum--;
printf("%d成功卖出一张票。余票为:%lld\n", *i, ticketNum);
}
else {
SetEvent(hevent);
break;
}
SetEvent(hevent);
}
printf("%d票卖完了。余票为:%lld\n", *i, ticketNum);
delete arg;
return 0;
}
// 使用信号量来卖票、总花费时间:11226ms
unsigned long WINAPI HandleSemapMethod(void* arg)
{
int* i = (int*)arg;
while (ticketNum > 0)
{
WaitForSingleObject(hsemaphore, INFINITE);
if (ticketNum > 0)
{
ticketNum--;
printf("%d成功卖出一张票。余票为:%lld\n", *i, ticketNum);
}
else {
// 让信号量+1
ReleaseSemaphore(hsemaphore, 1, NULL);
break;
}
ReleaseSemaphore(hsemaphore, 1, NULL);
}
printf("%d票卖完了。余票为:%lld\n", *i, ticketNum);
delete arg;
return 0;
}
// 使用临界区实现卖票同步,总花费时间:10423ms
unsigned long WINAPI HandleCriticalMethod(void* arg)
{
int* i = (int*)arg;
while (ticketNum > 0)
{
// 进入临界区
EnterCriticalSection(&g_cs);
if (ticketNum > 0)
{
ticketNum--;
printf("%d成功卖出一张票。余票为:%lld\n", *i, ticketNum);
}
else {
// 离开临界区
LeaveCriticalSection(&g_cs);
break;
}
LeaveCriticalSection(&g_cs);
}
printf("%d票卖完了。余票为:%lld\n", *i, ticketNum);
delete arg;
return 0;
}
// 互斥对象用来控制线程同步问题
int main()
{
// 获取当前时间
auto now = std::chrono::high_resolution_clock::now();
auto duration = now.time_since_epoch();
long long beginNanoSec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
/*
* CreateThread参数解释
* CreateThread(
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 安全属性,通常为NULL
_In_ SIZE_T dwStackSize, 新线程的初始栈大小(以字节为单位),写0的话默认为1M
_In_ LPTHREAD_START_ROUTINE lpStartAddress, 要执行的方法的地址
_In_opt_ __drv_aliasesMem LPVOID lpParameter, 传入方法中的参数
_In_ DWORD dwCreationFlags, 控制线程创建的标志。这可以是一个或多个值的组合,如 0(表示没有特殊标志)、CREATE_SUSPENDED(表示创建线程后挂起它,直到调用 ResumeThread)、STACK_SIZE_PARAM_IS_A_RESERVATION(表示 dwStackSize 参数指定了栈大小的保留大小,而不是提交大小)等。
_Out_opt_ LPDWORD lpThreadId 指向一个 DWORD 的指针,该 DWORD 接收新线程的线程标识符
);
*/
// 初始化临界区
InitializeCriticalSection(&g_cs);
// 创建100个线程去卖100亿张票
for (int i = 0; i < THREAD_NUM; i++)
{
int* index = new int;
*index = i;
handles[i] = CreateThread(NULL, 0, HandleCriticalMethod, index, 0, NULL);
}
// 等待所有的线程都执行完成
unsigned long ret = WaitForMultipleObjects(THREAD_NUM, handles, TRUE, INFINITE);
printf("WaitForMultipleObjects result: %ld\n", ret);
// 关闭所有句柄
for (int i = 0; i < THREAD_NUM; i++)
{
CloseHandle(handles[i]);
}
CloseHandle(hmutex);
CloseHandle(hevent);
CloseHandle(hsemaphore);
// 删除临界区
DeleteCriticalSection(&g_cs);
// 获取结束时间
now = std::chrono::high_resolution_clock::now();
duration = now.time_since_epoch();
long long endNanoSec = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
// 计算使用时间
long long useTime = endNanoSec - beginNanoSec;
printf("买票一共花了%lld毫秒\n", useTime);
}
C++——线程实现同步的4种方式(信号量、互斥对象、事件、临界区)
猜你喜欢
转载自blog.csdn.net/weixin_42789698/article/details/140578299
今日推荐
周排行