1. 线程相关函数:
1.1 CreateThread:windows系统函数
_beginthread:C/C++运行库提供的创建线程函数,如果要在多线程中使用C/C++运行库,需要使用该函数进行创建线程,该函数内部会初始化某些C运行时变量,并在内部调用CreateThread,里面会分配一个对象空间,用于保证c运行库部分接口的线程安全(如错误码),所以建议使用_beginthread创建线程
1.2 ExitThread:
_endthread:与_beginThread对应,如果使用_beginThread创建线程,但是使用ExitThread,就会出现内存泄露
1.3 TerminateThread:终止线程。线程外终止线程,如果是线程内终止线程,就是上面的ExitThread,_endthread。不过这几种方式都不建议使用,应该等线程执行完后自动结束
1.4 ResumeThread:恢复线程,恢复与挂起的次数需要相同才能唤醒
1.5 SuspendThread:挂起线程
1.6 SetThreadPriority:设置线程优先级
1.7 Sleep:睡眠,SleepEx:会有一个参数设置(bAlertable),其它有些API也有类似这个参数,这个参数设置为True,表示如果有异步IO这种回调过来,SleepEx就会提前结束了,如果是False,则和以前Sleep行为一致
1.8 GetThreadPriority:获取线程优先级
1.9 GetExitCodeThread:获取线程退出码,可以通过不断调用这个函数,判断出线程是否结束,如果返回STILL_ACTIVE表示线程正在执行,如果CreateThread时,传入的flag是延迟启动,获取到ExitCode也依旧是STILL_ACTIVE
2. 线程通信:
四种进程或线程同步互斥的控制方法
1、临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。
2、互斥量:为协调共同对一个共享资源的单独访问而设计的。
3、信号量:为控制一个具有有限数量用户资源而设计。
4、事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。
1. 互斥量与临界区的作用非常相似,但互斥量是可以命名的,也就是说它可以跨越进程使用。所以创建互斥量需要的资源更多,所以如果只为了在进程内部使用的话临界区会带来速度上的优势并能够减少资源占用量 。因为互斥量是跨进程的互斥量一旦被创建,就可以通过名字打开它。
2. 互斥量(Mutex),信号灯(Semaphore),事件(Event)都可以被跨越进程使用来进行同步数据操作,而其他的对象与数据同步操作无关,但对于进程和线程来讲,如果进程和线程在运行状态则为无信号状态,在退出后为有信号状态。所以可以使用WaitForSingleObject来等待进程和 线程退出。
3. 通过互斥量可以指定资源被独占的方式使用,但如果有下面一种情况通过互斥量就无法处理,比如现在一位用户购买了一份三个并发访问许可的数据库系统,可以根据用户购买的访问许可数量来决定有多少个线程/进程能同时进行数据库操作,这时候如果利用互斥量就没有办法完成这个要求,信号灯对象可以说是一种资源计数器。
2.1 事件(Event)
CreateEvent, SetEvent,ResetEvent,OpenEvent
(1)如果是跨进程访问事件,则需要对事件命名。
(2)事件是否要自动恢复
(3)事件的初始状态设置
2.2 信号量(semaphore)
CreateSemaphore,ReleaseSemaphore,OpenSemaphore.
2.3 互斥量(mutex)
CreateMutex,OpenMutex,ReleaseMutex.
2.4 临界区(Critical section):临界区不支持垮进程访问。
InitializeCriticalSection,DeleteCriticalSection,EnterCriticalSection,LeaveCriticalSection
(1)每个共享资源使用一个CRITICAL_SECTION变量
(2)不要长时间运行关键代码段。
(3)如果需要同时访问多个资源,则可以连续调用EnterCriticalSection
(4)Critical Section不是os核心对象,如果进入临界区的线程挂了,将无法释放临界资源,这个缺点在Mutex中得到弥补。
2.5 等待核心对象
WaitForSingleObject
WaitForMultipleObjects
代码如下
SECTION("CreateThread")
{
// c++11写法,分配默认堆栈大小
std::thread t1 = thread(TestStdThread);
t1.detach();
unsigned int thread_id = 0;
auto thread_handle = _beginthreadex(nullptr, 0, BeginThreadFunc, (LPVOID)1, 0, &thread_id);
// 通过waitfor等待线程结束
if (WAIT_OBJECT_0 == WaitForSingleObject((HANDLE)thread_handle, 1000))
{
cout << "wait success" << endl;
}
else
{
cout << "wait time out" << endl;
}
// 通过GetExitCode等待线程结束
DWORD exitCode1 = 0;
GetExitCodeThread((HANDLE)thread_handle, &exitCode1);
while (exitCode1 == STILL_ACTIVE)
{
GetExitCodeThread((HANDLE)thread_handle, &exitCode1);
puts("Thread 1 is still running!");
Sleep(1000);
}
std::cout << exitCode1;
TerminateThread((HANDLE)thread_handle, 0); // 可以强制结束线程
CloseHandle((HANDLE)thread_handle);
}
SECTION("CriticalSection")
{
// 临界区
RTL_CRITICAL_SECTION critical_section;
InitializeCriticalSection(&critical_section);
EnterCriticalSection(&critical_section);
LeaveCriticalSection(&critical_section);
DeleteCriticalSection(&critical_section);
}
SECTION("Mutex")
{
// 互斥量
HANDLE h_mutex = CreateMutex(NULL, FALSE, L"test_mutex"); // h_mutex默认是激活状态,没有线程拥有
HANDLE h_mutex_2 = CreateMutex(NULL, FALSE, L"test_mutex");
CloseHandle(h_mutex_2);
if (WAIT_OBJECT_0 == WaitForSingleObject(h_mutex, 3000)) // WaitForSingleObject会将等到的互斥量设置为未激活状态,等到的这个线程拥有它
{
ReleaseMutex(h_mutex);
}
CloseHandle(h_mutex);
}
SECTION("Semaphores")
{
// 信号量
HANDLE h_semaphores = CreateSemaphore(nullptr, 2, 10, nullptr);
LONG pre_count = 0;
BOOL ret = ReleaseSemaphore(h_semaphores, 2, &pre_count);
CHECK(pre_count == 2);
ret = ReleaseSemaphore(h_semaphores, 2, &pre_count);
CHECK(pre_count == 4);
if (WAIT_OBJECT_0 == WaitForSingleObject(h_semaphores, 3000)) // WaitForSingleObject会占用一个信号量
{
ret = ReleaseSemaphore(h_semaphores, 2, &pre_count);
CHECK(pre_count == 5);
}
int pre = 0;
}
SECTION("Event")
{
// 事件
HANDLE h_event = CreateEvent(nullptr, FALSE, TRUE, NULL);
// WaitForMultipleObjectsEx
}