1. 程式人生 > >建立執行緒——_beginthread 和 _beginthreadex【方法2】

建立執行緒——_beginthread 和 _beginthreadex【方法2】

並不是Windows標準API,建立執行緒函式,該函底層呼叫CreateThread。

標頭檔案

#include <process.h>

函式原型

unsigned long _beginthread(  
    void(_cdecl *start_address)(void *), //宣告為void (*start_address)(void *)形式 
    unsigned stack_size, //是執行緒堆疊大小,一般預設為0 
    void *arglist //向執行緒傳遞的引數,一般為結構體
 );
typedef unsigned int uintptr_t;
typedef unsigned (__stdcall* _beginthreadex_proc_type)(void*); uintptr_t _beginthreadex( void* _Security, //執行緒安全屬性 unsigned _StackSize, //執行緒堆疊大小 _beginthreadex_proc_type _StartAddress, //執行緒函式地址 void* _ArgList, //傳遞給執行緒函式的地址 unsigned _InitFlag, //指定執行緒是否立即啟動 unsigned
* _ThrdAddr //儲存執行緒id號 );

安全屬性

SECURITY_ATTRIBUTES結構包含一個物件的安全描述符,並指定檢索到指定這個結構的控制代碼是否是可繼承的。這個結構為很多函式建立物件時提供安全性設定。如:CreateFile,CreatePipe,CreateProcess,RegCreateKeyEx,RegSaveKeyEx。

typedef struct _SECURITY_ATTRIBUTES {
    DWORD nLength;               //結構體的大小,可用SIZEOF取得 
    LPVOID lpSecurityDescriptor;
//安全描述符 BOOL bInheritHandle; //安全描述的物件能否被新建立的程序繼承 } SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;

執行緒終止

執行緒函式退出。 執行緒使用的堆疊被釋放。 dwExitCode設定為執行緒函式的返回值。 遞減核心中的code值,讓核心的引用計數減一。

  • 結束執行緒呼叫,終止自己

    VOID WINAPI ExitThread(
      __in DWORD dwExitCode	  // 執行緒結束時的退出碼
    );
    
  • 由當前執行緒終止其他執行緒

    BOOL WINAPI TerminateThread(
      __in_out HANDLE hThread,  // 終止的執行緒控制代碼
      __in DWORD dwExitCode     // 退出碼
    );
    
  • 釋放執行緒空間、釋放執行緒TLS空間、呼叫ExiteThread結束執行緒

    void _endthread(void); 	
    // retval:設定的執行緒結束碼,與ExiteThread函式的引數功能一樣,
    //其實這個函式釋放執行緒TLS空間,再呼叫ExiteThread函式,但沒有釋放執行緒空間。
    void _endthreadex(unsigned retval);	
    

    可以顯示的呼叫這兩個函式來結束執行緒。系統從執行緒啟動函式返回時,也會自動呼叫相應的結束 執行緒函式,收回分配給執行緒的資源。

區別

兩組函式都是用來建立和結束執行緒的。這兩對函式的不同點如下:

  1. 從形式上開,_beginthreadex()更像CreateThread()。_beginthreadex()比_beginthread()多3個引數:intiflag,security和threadaddr。
  2. 兩種建立方式的執行緒函式不同。_beginthreadex()的執行緒函式必須呼叫_stdcall呼叫方式,而且必須返回一個unsigned int型的退出碼。
  3. _beginthreadex()在建立執行緒失敗時返回0,而_beginthread()在建立執行緒失敗時返回-1。這一點是在檢查返回結果是必須注意的。
  4. 如果是呼叫_beginthread()建立執行緒,並相應地呼叫_endthread()結束執行緒時,系統自動關閉執行緒控制代碼;而呼叫_beginthreadx()建立執行緒,並相應地呼叫_endthreadx()結束執行緒時,系統不能自動關閉執行緒控制代碼。因此呼叫_beginthreadx()建立執行緒還需程式設計師自己關閉執行緒控制代碼,以清除執行緒的地址空間。

例項

例項一:

#include <iostream>
#include <windows.h>
#include <process.h>
using namespace std;

unsigned int WINAPI ThreadProFunc(void *pParam);
int main(int argc, char **argv)
{
	HANDLE hThread;
	unsigned int threadId;
	hThread = (HANDLE)_beginthreadex(NULL, NULL, ThreadProFunc, NULL, 0, &threadId);
	for (int i = 0; i < 100; i++) {
		cout << "nihao" << endl;
	}
	CloseHandle(hThread);	//關閉執行緒控制代碼
	system("pause");
	return 0;
}

unsigned int WINAPI ThreadProFunc(void *pParam)
{
	for (int i = 0; i < 100; i++) {
		cout<<"hello\n";
	}
	return 0;
}

槍戰模式 在這裡插入圖片描述

例項二:

#include <Windows.h>
#include <process.h>
#include <iostream>
using namespace std;

typedef struct  _STRUCT_DATA_
{
	int id; //用於標識出票id
	int tickets;
}_DATA, *_pDATA;

//CRITICAL_SECTION g_cs;
unsigned __stdcall Fun1(LPVOID lpParam);
unsigned __stdcall Fun2(LPVOID lpParam);

void main()
{
	HANDLE hThread[2] = { NULL,NULL };
	unsigned threadid[2] = { 0 };
	_DATA stru_data;

	stru_data.id = 0;
	stru_data.tickets = 200;

	hThread[0] = (HANDLE)_beginthreadex(NULL, 0, Fun1, &stru_data, 0, &threadid[0]);
	hThread[1] = (HANDLE)_beginthreadex(NULL, 0, Fun2, &stru_data, 0, &threadid[1]);

	//InitializeCriticalSection(&g_cs);
	Sleep(4000);
	//LeaveCriticalSection(&g_cs);

}

unsigned __stdcall Fun1(LPVOID lpParam)
{
	_pDATA data = (_pDATA)lpParam;
	while (TRUE)
	{
		//EnterCriticalSection(&g_cs);
		if (data->tickets > 0)
		{
			Sleep(1);
			cout << "fun1: " << data->id++ ;
			cout << " *** thread 1 :sell ticket: " << data->tickets-- << endl;
			//LeaveCriticalSection(&g_cs);
		}
		else
		{
			//LeaveCriticalSection(&g_cs);
			break;
		}
	}
	return 0;
}

unsigned __stdcall Fun2(LPVOID lpParam)
{
	_pDATA data = (_pDATA)lpParam;
	while (TRUE)
	{
		//EnterCriticalSection(&g_cs);
		if (data->tickets > 0)
		{
			Sleep(1);
			cout << "fun2: " << data->id++ ;
			cout << " === thread 2:sell ticket: " << data->tickets-- << endl;
		//	LeaveCriticalSection(&g_cs);
		}
		else
		{
			//LeaveCriticalSection(&g_cs);
			break;
		}
	}
	return 0;
}

在這裡插入圖片描述