程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C++拾遺--多線程:多線程的引入

C++拾遺--多線程:多線程的引入

編輯:C++入門知識

C++拾遺--多線程:多線程的引入


C++拾遺--多線程:多線程的引入

前言

多線程是編程中的一個重要內容。多核時代使多線程成為一種可能,顯然,一件事情多個人干,效率一定會提升。下面來看下C語言中是如何使用多線程的。

正文

1.CreateThread

先來看一個實例

 

#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 
#include 

DWORD WINAPI run(void *p)
{
	char *mess = (char*)p;
	printf(線程%d,彈窗
, GetCurrentThreadId());
	char threadId[20];
	sprintf(threadId, 線程%d, GetCurrentThreadId());
	MessageBoxA(0, mess, threadId, 0);
	return 0;
}
int main(void)
{
	printf(******C語言多線程演示***by David***
);
	char *mess[] = { 123, 456, 789 };
	HANDLE handles[3];
	for (int i = 0; i < sizeof(mess) / sizeof(*mess); i++)
	{
		handles[i] = CreateThread(NULL, 0, run, mess[i], 0, NULL);
	}
	WaitForMultipleObjects(3, handles, 1, INFINITE);
	return 0;
}
運行

 

\

 

異步彈出了三個窗口,並打印了各自的線程號。若是有沒看懂的地方,下面有詳細解釋:

1.handle是句柄,在windows中用句柄來標識對象。本質很簡單 typedef void * HANDLE;

2.CreateThread()用來創建線程。原型

HANDLE WINAPI CreateThread(
LPSECURITY_ATTRIBUTES lpThreadAttributes, //內核對象的安全屬性
SIZE_T dwStackSize, //線程棧大小
LPTHREAD_START_ROUTINE lpStartAddress, //線程函數地址
LPVOID lpParameter, //傳給線程函數的參數
DWORD dwCreationFlags, //控制位
LPDWORD lpThreadId //獲取線程id
);

參數解釋:

第一個參數是線程內核對象的安全屬性,一般傳入NULL表示使用默認設置。

第二個參數是線程棧空間的大小。傳入0表示使用默認大小(1MB)。

第三個參數是新線程所執行的線程函數地址,多個線程可以使用同一個函數地址。

第四個參數是傳給線程函數的參數。typedef void * LPVOID

第五個參數是用來控制線程的創建,0表示創建後立即執行。

第六個參數是傳出參數,用來獲得線程的id。顯然,傳入NULL,表示調用者並不想知道線程的id。

返回值:線程句柄

3.線程函數的聲明。#define WINAPI __stdcall (vs2013)typedef unsigned long DWORD。其中,__stdcall是指C/CPP中函數的調用方式。主要有兩點:1.實參從右向左入棧。2.調用者負責清空參數棧。

4.線程等待函數

DWORD WINAPI WaitForMultipleObjects(
DWORD nCount, //內核對象的個數
CONST HANDLE *lpHandles, //句柄數組的地址
BOOL bWaitAll, //是否等待所有
DWORD dwMilliseconds //等待的最大時間,單位毫秒,INFINITE表示無限等待
);

函數功能:讓線程進入等待轉態,直到條件觸發。內核對象在運行期間處於未觸發的狀態,直到執行結束。

5.線程函數類型是

typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);

更簡潔的是

typedef unsigned long (__stdcall *pfun)(void*);

 

2._beginthreadex

函數原型

uintptr_t __cdecl _beginthreadex(
void* _Security,
unsigned _StackSize,
_beginthreadex_proc_type _StartAddress,
void* _ArgList,
unsigned _InitFlag,
unsigned* _ThrdAddr
);

它的參數類型和CreateThread基本一致,只是線程函數類型稍有不同。線程函數類型是

typedef unsigned (__stdcall *_beginthreadex_proc_type)(void*);

 

3._beginthread

CreateThread的調用過於復雜,下面我們玩兒個簡單的,我們用多個線程打印 Hello World

 

#include 
#include 
#include 
#include 
void hello(void *p)
{
	printf(線程%d, say Hello World
, GetCurrentThreadId());
}
int main()
{
	printf(******C語言多線程演示***by David***
);
	HANDLE handles[5];
	for (int i = 0; i < 5; i++)
	{
		handles[i] = _beginthread(hello, 0, NULL);
	}
	WaitForMultipleObjects(5, handles, 1, INFINITE);
	getchar();
	return 0;
}
運行

 

\
 

_beginthread的原型

uintptr_t _beginthread(
_beginthread_proc_type _StartAddress, //線程函數的地址
unsigned _StackSize, //線程棧的大小
void* _ArgList //線程函數的參數
);

函數功能:使用指定線程函數創建線程,並返回線程句柄。

幾點解釋:

1.typedef unsigned int * uintptr_t;

2.typedef void(__cdecl *_beginthread_proc_type)(void*); _beginthread_proc_type就是一函數指針類型,我們提供的線程函數應該如此設計:只有一個參數,類型為void*,且返回值類型是void。

 

CreateThread和_beginthread的使用說明:

 

從函數參數可以看出,CreateThread用於對所創建的線程進行精細控制。在很多參數處於默認設置下,建議使用參數簡單的_beginthread。兩者所需的線程函數類型不同。

 

 

總結

 

使用多線程,就要先寫好線程函數,然後調用相關函數創建線程即可。由於_beginthread傳參簡單,一般情況下,使用_beginthread創建多線程。


 

 

 

 

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved