windows多線程(二) 等待線程返回


多線程編程中,有時我們需要等待某一線程完成了特定的操作后再繼續做其他事情,要實現這個目的,可以使用Windows API函數WaitForSingleObject,或者WaitForMultipleObjects。這兩個函數都會等待Object被標為有信號(signaled)時才返回。只要是Windows創建的Object都會被賦予一個狀態量。如果Object被激活了,或者正在使用,那么該Object就是無信號,也就是不可用;另一方面,如果Object可用了,那么它就恢復有信號了。

一、 等待單個線程返回 WaitForSingleObject

1. 函數原型


DWORD WINAPI WaitForSingleObject(
    _In_ HANDLE hHandle,
    _In_ DWORD dwMilliseconds
    );

2.參數說明

第一個參數 _In_ HANDLE hHandle 是對象的句柄,可以是以下幾種:

  • Change notification
  • Console input
  • Event
  • Memory resource notification
  • Mutex
  • Process
  • Semaphore
  • Thread
  • Waitable timer

第二個參數 _In_ DWORD dwMilliseconds 為等待時間,以毫秒為單位。參數dwMilliseconds有兩個具有特殊意義的值:0和INFINITE。若為0,則該函數立即返回;若為INFINITE,則線程一直被掛起,直到hHandle所指向的對象變為有信號狀態時為止。

3.返回值

  • WAIT_ABANDONED 0x00000080:當hHandle為mutex時,如果擁有mutex的線程在結束時沒有釋放核心對象會引發此返回值。
  • WAIT_OBJECT_0 0x00000000 :指定的對象出有有信號狀態
  • WAIT_TIMEOUT 0x00000102:等待超時
  • WAIT_FAILED 0xFFFFFFFF :出現錯誤,可通過GetLastError得到錯誤代碼

4.實例

1.參數 dwMilliseconds 為0,則該函數立即返回


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

DWORD WINAPI  ThreadFunc(LPVOID);

int main()
{
	HANDLE hThread;

	hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 創建線程
	printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid
	
	WaitForSingleObject(hThread,0);	//不等待,直接返回
	return 0;
}

DWORD WINAPI  ThreadFunc(LPVOID p)
{
	Sleep(10000); //睡眠10秒
	printf("我是子線程, pid = %d\n", GetCurrentThreadId());   //輸出子線程pid
	
	return 0;
}

輸出如下圖,主線程不等待子線程返回,直接返回。

2.參數 dwMilliseconds 為5000,等待5秒后返回。



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

DWORD WINAPI  ThreadFunc(LPVOID);

int main()
{
	HANDLE hThread;

	hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 創建線程
	printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid
	
	WaitForSingleObject(hThread,5000);	//等待5s
	return 0;
}

DWORD WINAPI  ThreadFunc(LPVOID p)
{
	printf("我是, pid = %d 的子線程\n", GetCurrentThreadId());   //輸出子線程pid
	Sleep(10000); //睡眠10秒
	printf(" pid = %d 的子線程退出\n", GetCurrentThreadId());    //延時10s后輸出
	
	return 0;
}

輸出如下圖,主線程等待子線程5秒后,子線程還沒有執行完,WaitForSingleObject就返回了。

3.參數 dwMilliseconds 為INFINITE,則線程一直被掛起,直到hHandle所指向的對象變為有信號狀態時為止


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

DWORD WINAPI  ThreadFunc(LPVOID);

int main()
{
	HANDLE hThread;

	hThread = CreateThread(NULL, 0, ThreadFunc, 0, 0, NULL); // 創建線程
	printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid
	
	WaitForSingleObject(hThread,INFINITE);	//一直等待,直到子線程返回
	return 0;
}

DWORD WINAPI  ThreadFunc(LPVOID p)
{
	printf("我是, pid = %d 的子線程\n", GetCurrentThreadId());   //輸出子線程pid
	Sleep(10000); //睡眠10秒
	printf(" pid = %d 的子線程退出\n", GetCurrentThreadId());   //延時10s后輸出
	
	return 0;
}

輸出如下圖,主線程一直等待直到子線程還沒有執行完畢。

二、 等待多個線程返回 WaitForMulitpleObjects

1. 函數原型

DWORD WINAPI WaitForMultipleObjects(
  _In_       DWORD   nCount,
  _In_ const HANDLE  *lpHandles,
  _In_       BOOL    bWaitAll,
  _In_       DWORD   dwMilliseconds
);

2.參數說明

  • 第一個參數 DWORD dwCount 為等待的內核對象個數,可以是0到MAXIMUM_WAIT_OBJECTS(64)中的一個值。
  • 第二個參數 CONST HANDLE* phObjects 為一個存放被等待的內核對象句柄的數組
  • 第三個參數 BOOL bWaitAll 是否等到所有內核對象為已通知狀態后才返回,如果為TRUE,則只有當等待的所有內核對象為已通知狀態時函數才返回,如果為FALSE,則只要一個內核對象為已通知狀態,則該函數返回。
  • 第四個參數 DWORD dwMilliseconds 為等待時間,和WaitForSingleObject中的dwMilliseconds參數類似。

3.實例

1.參數 bWaitAll 為 false,只要一個內核對象為已通知狀態,則該函數返回。


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

const unsigned int THREAD_NUM = 10;
DWORD WINAPI  ThreadFunc(LPVOID);

int main()
{
	printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid
	HANDLE hThread[THREAD_NUM];
	for (int i = 0; i < THREAD_NUM; i++)
	{
		hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 創建線程
	}
	
	WaitForMultipleObjects(THREAD_NUM,hThread,false, INFINITE);	//只要有一個線程返回就結束
	return 0;
}

DWORD WINAPI  ThreadFunc(LPVOID p)
{
	int n = *(int*)p;
	Sleep(1000*n); //第 n 個線程睡眠 n 秒
	printf("我是, pid = %d 的子線程\n", GetCurrentThreadId());   //輸出子線程pid
	printf(" pid = %d 的子線程退出\n", GetCurrentThreadId());   

	return 0;
}

輸出如下圖,只要有一個線程返回就不再等待其它線程。

2.參數 bWaitAll 為 true,等待所有線程返回。



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

const unsigned int THREAD_NUM = 10;
DWORD WINAPI  ThreadFunc(LPVOID);

int main()
{
	printf("我是主線程, pid = %d\n", GetCurrentThreadId());  //輸出主線程pid
	HANDLE hThread[THREAD_NUM];
	for (int i = 0; i < THREAD_NUM; i++)
	{
		hThread[i] = CreateThread(NULL, 0, ThreadFunc, &i, 0, NULL); // 創建線程
	}
	
	WaitForMultipleObjects(THREAD_NUM,hThread,true, INFINITE);	//一直等待,直到所有子線程全部返回
	return 0;
}

DWORD WINAPI  ThreadFunc(LPVOID p)
{
	int n = *(int*)p;
	Sleep(1000*n);  //第 n 個線程睡眠 n 秒
	printf("我是, pid = %d 的子線程\t", GetCurrentThreadId());   //輸出子線程pid
	printf(" pid = %d 的子線程退出\n\n", GetCurrentThreadId());   //延時10s后輸出

	return 0;
}

輸出如下圖,主線程等待所有線程返回。

好了,關於WaitForSingleObject 和 WaitForMultipleObjects這兩個函數的介紹就先到這里。 另外上面圖中有一行顯示了三列,這是正常現象,是由於沒有做線程同步造成的,關於線程同步的知識,將在以后的文章中介紹。畢竟多線程的精髓就是線程同步問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM