基础篇包括了4个小内容。
1.基本的线程操作
2.线程对象封装
3.互斥和临界区
4.同步操作
线程函数
win32 | c | |
---|---|---|
创建线程 | CreateThread | _beginthread _beginthreadex |
恢复线程 |
ResumeThread | |
挂起线程 |
SuspendThread | |
退出线程 |
ExitThread | _endthread _endthreadex |
强制结束线程 |
TerminateThread | |
释放线程对象 |
CloseHandle | |
设置线程优先级 | SetThreadPriority | |
线程回调函数 |
ThreadProc |
Demo1
#include
#include
#include
unsigned __stdcall MyThreadFunc(void* p)
{
printf("线程启动,停留3秒\n");
Sleep(3000);
printf("线程退出\n");
_endthreadex(0); // c语言退出线程函数
return 0;
}
int main()
{
HANDLE hThread;
unsigned threadID;
hThread = (HANDLE)_beginthreadex( // c语言创建线程函数
NULL, // 安全属性
0, // 线程堆栈大小
&MyThreadFunc, // 函数指针,指向线程函数
NULL, // 函数参数,输入到线程函数
0, // 新线程的初始状态,0表示立即执行,CREATE_SUSPENDED 表示创建之后挂起
&threadID); // 返回线程ID
DWORD dw = WaitForSingleObject(hThread, // 资源句柄, 这里是线程的句柄
INFINITE); // INFINITE-无线等待 数字-等待时长(毫秒)
switch (dw) // 返回值
{
case WAIT_OBJECT_0:
// 等到第0个对象
break;
case WAIT_TIMEOUT:
// 等待超时
break;
case WAIT_FAILED:
// 输入句柄错误
break;
}
CloseHandle(hThread);
system("Pause");
return 0;
}
通过封装可以定义自己的线程类
Demo2
#include
#include
DWORD WINAPI ThreadFunWrapper(LPVOID lpParam);
class MyThread
{
public:
HANDLE hSendthread;
MyThread(void);
~MyThread(void);
void StartThread();
void StopThread();
void ThreadFun();
};
MyThread::MyThread(void) // 创建线程
{
hSendthread = CreateThread(0,
0,
ThreadFunWrapper, // ThreadFun()是类成员函数,createthread不能接受成员函数的指针,所以需要创建一个封装函数。
this, // 实例指针,传递给封装函数
CREATE_SUSPENDED,
0);
};
MyThread::~MyThread(void)
{
TerminateThread(hSendthread, 0); // 强制删除线程
CloseHandle(hSendthread);
};
void MyThread::StartThread()
{
ResumeThread(hSendthread);
};
void MyThread::StopThread()
{
SuspendThread(hSendthread);
};
void MyThread::ThreadFun()
{
printf("线程启动,停留3秒\n");
Sleep(3000);
printf("线程退出\n");
ExitThread(0); // windows api线程结束函数
};
DWORD WINAPI ThreadFunWrapper(LPVOID lpParam) // 封装函数
{
MyThread * pMyThread =
reinterpret_cast(lpParam);
pMyThread->ThreadFun();
return 0;
}
int main()
{
MyThread tr; // 默认创建的线程是挂起状态
tr.StartThread(); // 从挂起状态恢复
WaitForSingleObject(tr.hSendthread,10000); // 等待线程退出
system("Pause");
return 0;
}
互斥 | 临界区 | |
---|---|---|
类型 | HANDLE hMutex |
CRITICAL_SECTION g_cs; |
创建 |
CreateMutex |
InitializeCriticalSection(&g_cs); |
释放 |
CloseHandle |
DeleteCriticalSection(&g_cs); |
进入lock |
WaitForSingleObject WaitForMultipleObjects |
EnterCriticalSection(&g_cs); |
离开unlock |
ReleaseMutex |
LeaveCriticalSection(&g_cs); |
Mutex可以和waitfor系列函数搭配使用,且支持跨进程,功能强大。CriticalSection容易理解使用较为简单。
demo3
#include
#include
#include
CRITICAL_SECTION g_cs;
unsigned __stdcall MyThreadFunc(void* pArguments)
{
// EnterCriticalSection(&g_cs); // 进入临界区
for (int i = 0; i < 100; i++)
putchar('0' + *(int*)pArguments);
putchar('\n');
// LeaveCriticalSection(&g_cs); // 退出临界区
_endthreadex(0);
return 0;
}
int main()
{
HANDLE hThread[5];
unsigned threadID[5];
int id[5] = { 1, 2, 3, 4, 5 };
InitializeCriticalSection(&g_cs);
int i;
for (i = 0; i < 5; i++)
hThread[i] = (HANDLE)_beginthreadex(NULL, 0, &MyThreadFunc, &id[i], 0, &threadID[i]);
DWORD dw = WaitForMultipleObjects( // 等所有线程完成工作
5, // 等待事件的总数量
hThread, // 事件数组
TRUE, // TRUE-等待全部事件 FALSE-等待任一事件
10000); // 最长等待多长事件
switch (dw) // 处理返回值
{
case WAIT_OBJECT_0 + 0:
break;
case WAIT_OBJECT_0 + 1:
break;
case WAIT_OBJECT_0 + 2:
break;
case WAIT_OBJECT_0 + 3:
break;
case WAIT_OBJECT_0 + 4:
break;
case WAIT_TIMEOUT:
break;
case WAIT_FAILED:
break;
default:
break;
}
for (i = 0; i < 5; i++) // 释放所有线程句柄
CloseHandle(hThread[i]);
DeleteCriticalSection(&g_cs);
system("Pause");
return 0;
}
信号量 | 事件 | |
---|---|---|
初始化 | CreateSemaphore | CreateEvent |
获取访问权 |
OpenSemaphore | OpenEvent |
P操作 |
WaitForSingleObject WaitForMultipleObjects |
WaitForSingleObject WaitForMultipleObjects |
V操作 |
ReleaseSemaphore | SetEvent |
信号量支持多个资源,类似操作系统中的记录型信号量,可用于多个同类型资源管理。event事件主要用于实现操作同步。
Demo4同步
下例中有两组同步关系,停车|开门,关门|开车。用两个event分别表示。
加入PV操作后可得,停车V(s1)|P(s1)开门,关门V(s2)|P(s2)开车。
#include
#include
HANDLE hevent1, hevent2;
HANDLE hevent_exit;
DWORD WINAPI SellerThreadFunc(void* p);
DWORD WINAPI DriverThreadFunc(void* p);
int main()
{
CreateMutex(NULL, FALSE, NULL);
srand(342443);
DWORD sellerthreadid, driverthreadid;
// CreateEvent函数说明
// 参数2 指定将事件对象创建成手动复原还是自动复原。FALSE-自动复位,当一个等待线程(WaitForSingleObject)被释放以后自动将事件状态复位到无信号状态。TRUE - 人工复位,调用ResetEvent函数将事件的状态复位到无信号状态。
// 参数3 指定事件对象的初始状态。TRUE-初始状态为有信号状态;FALSE-初始状态为无信号状态。
hevent1 = CreateEvent(NULL, TRUE, FALSE, _T("s1")); // event对象为人工复位模式
hevent2 = CreateEvent(NULL, FALSE, FALSE, _T("s2")); // event对象为自动复位模式
hevent_exit = CreateEvent(NULL, TRUE, FALSE, _T("ext"));// 人工复位的事件,初始状态为有信号状态
HANDLE h[2];
h[0] = CreateThread(0, 0, SellerThreadFunc, NULL, 0, &sellerthreadid);
h[1] = CreateThread(0, 0, DriverThreadFunc, NULL, 0, &driverthreadid);
Sleep(10000); // 20秒后发送结束信号
SetEvent(hevent_exit); // 人工复位的事件,初始状态为有信号状态
WaitForMultipleObjects(2, h, TRUE, INFINITE); // 等待所有线程退出
CloseHandle(hevent1);
CloseHandle(hevent2);
CloseHandle(hevent_exit);
CloseHandle(h[0]);
CloseHandle(h[1]);
system("Pause");
return 0;
}
DWORD WINAPI SellerThreadFunc(void* p)
{
while (1)
{
Sleep(rand() % 1000);
printf("售票员: 关门 V(s2)\n");
SetEvent(hevent1);
Sleep(rand() % 1000);
printf("售票员: 售票\n");
Sleep(rand() % 1000); // 随机等待0~999毫秒
WaitForSingleObject(hevent2, INFINITE);
printf("售票员: 开门 P(s1)\n");
DWORD dw = WaitForSingleObject(hevent_exit, 0); // 检测结束事件,不等待。
if (dw == WAIT_OBJECT_0) // 如果是结束事件则退出线程。
ExitThread(0);
}
}
DWORD WINAPI DriverThreadFunc(void* p)
{
while (1)
{
WaitForSingleObject(hevent1, INFINITE);
ResetEvent(hevent1); // event对象为人工复位模式
Sleep(rand() % 1000);
printf("司 机: 开车 P(s2)\n");
Sleep(rand() % 1000);
printf("司 机: 驾驶\n");
Sleep(rand() % 1000);
printf("司 机: 停车 V(s1)\n");
SetEvent(hevent2);
DWORD dw = WaitForSingleObject(hevent_exit, 0);
if (dw == WAIT_OBJECT_0)
ExitThread(0);
}
}