執行緒編程

執行緒是進程中的一個實體,是被系統獨立調度和分配的基本單位。一個進程可以有多個執行緒,一個執行緒必須有一個父進程,執行緒自己不擁有系統資源,只有運行必須的一些數據結構,但它可以與同屬一個進程的其他執行緒共享進程所擁有的全部資源,一個執行緒可以創建和撤銷另一個執行緒,同一個進程中的多個執行緒之間可以並發執行。

基本介紹

  • 中文名:執行緒編程
  • 作用:由於執行緒之間的相互制約
  • 狀態:就緒、阻塞、和運行
  • 區域:臨界區
執行緒,多執行緒,執行緒同步,臨界區,互斥量,信號量,事 件,臨界區對象,Windows多執行緒,

執行緒

執行緒是進程中的一個實體,是被系統獨立調度和分配的基本單位。一個進程可以有多個執行緒,一個執行緒必須有一個父進程,執行緒自己不擁有系統資源,只有運行必須的一些數據結構,但它可以與同屬一個進程的其他執行緒共享進程所擁有的全部資源,一個執行緒可以創建和撤銷另一個執行緒,同一個進程中的多個執行緒之間可以並發執行。

多執行緒

由於執行緒之間的相互制約,致使執行緒在運行中呈現出間斷性,執行緒也有就緒、阻塞、和運行3種基本狀態,所以,在一個進程中可以創建幾個執行緒來提高程式的執行效率,並且有些程式還通過採用多執行緒技術來同時執行多個不同的代碼模組。
在一般情況下,創建一個執行緒是不能提高程式的執行效率的,所以要創建多個執行緒。但是多個執行緒同時運行的時候可能調用執行緒函式,在多個執行緒同時對同一個記憶體地址進行寫入,由於CPU時間調度上的問題,寫入數據會被多次的覆蓋,所以就要使執行緒同步。

執行緒同步

即當有一個執行緒在對記憶體進行操作時,其他執行緒都不可以對這個記憶體地址進行操作,直到該執行緒完成操作,
其他執行緒才能對該記憶體地址進行操作,而其他執行緒又處於等待狀態,目前實現執行緒同步的方法有很多,例如:臨界區(critical section)、事件(event)、信號量(semaphore)、互斥量(mutex)。

臨界區

通過對多執行緒的串列化來訪問公共資源或一段代碼,速度快,適合控制數據訪問。在任意時刻只允許一個執行緒對共享資源進行訪問,如果有多個執行緒試圖訪問公共資源,那么在有一個執行緒進入後,其他試圖訪問公共資源的執行緒將被掛起,並一直等到進入臨界區的執行緒離開,臨界區在被釋放後,其他執行緒才可以搶占。

互斥量

採用互斥對象機制。 只有擁有互斥對象的執行緒才有訪問公共資源的許可權,因為互斥對象只有一個,所以能保證公共資源不會同時被多個執行緒訪問。互斥不僅能實現同一應用程式的公共資源安全共享,還能實現不同應用程式的公共資源安全共享

信號量

它允許多個執行緒在同一時刻訪問同一資源,但是需要限制在同一時刻訪問此資源的最大執行緒數目

事 件

通過通知操作的方式來保持執行緒的同步,還可以方便實現對多個執行緒的優先權比較的操作

臨界區對象

定義在數據段中的一個SECURITY_ATTRIBUTES結構體,Windows內部使用這個結構記錄一些信息,確保在同一時間只有一個執行緒訪問該數據段中的數據。
臨界區的使用步驟
1.初始化一個SECURITY_ATTRIBUTES結構,在臨界區對象之前,需要定於全局SECURITY_ATTRIBUTES結構體變數,在調用CreateThread函式前調用InitializeCriticalSection(LPC RITICAL_SECTION lpCriticalSection)函式初始化臨界區對象。
2.申請進入一個臨界區。線上程函式中要對保護的數據進行操作前,可以通過調用 EnterCriticalSection(LPC RITICAL_SECTION lpCriticalSection)函式申請進入臨界區,由於在同一時間內,只允許一個執行緒進入臨界區,所以在申請的時候如果有一個執行緒進入到臨界區,則該函式就會一直等到那個執行緒執行完臨界區代碼。
3.離開臨界區。當執行完臨界區代碼後,需要調用LeaveCriticalSection(LPC RITICAL_SECTION lpCriticalSection)函式吧臨界區交還給系統。
4.刪除臨界區,當不需要臨界區是可以調用DeleteCriticalSection(LPC RITICAL_SECTION lpCriticalSection)函式將臨界區對象刪除。
C++ 11 多執行緒
在 ISO C++ 11 標準中,<thread>頭檔案在std命名空間中引入了thread類。
std::thread類說明
構造函式
構造一個新的執行緒對象
析構函式
析構一個執行緒對象,該執行緒必須被join過或者被detach過
operator=
移動執行緒對象
joinable
檢查這個執行緒是否可以被join
get_id
返回執行緒的ID號
native_handle
返回執行緒的原生句柄
hardware_concurrency
返回同步的執行緒數量(公有靜態函式)
join
等待執行緒運行完畢
detach
允許執行緒脫離句柄的控制
swap
交換兩個執行緒對象
C++ 11 多執行緒同步的代碼
#include<iostream>#include<thread>#include<mutex>#include<chrono>usingnamespacestd;mutexm;voidthreadFunc(intnum){for(inti=0;i<10;++i){m.lock();cout<<"這是第"<<num<<"個執行緒。"<<endl;m.unlock();this_thread::sleep_for(chrono::milliseconds(500));}}intmain(){threadt1(threadFunc,1);threadt2(threadFunc,2);threadt3(threadFunc,3);threadt4(threadFunc,4);t1.join();t2.join();t3.join();t4.join();return0;}

Windows多執行緒

CreateThread函式說明
編程時,如果調用CreateThread函式,系統將創建一個進程和一個主執行緒。CreateThread將在主執行緒的基礎上創建一個新執行緒,如果調用成功返回新執行緒的句柄,函式調用格式:
HANDLE WINAPI CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId);
lpThreadAttributes
指向SECURITY_ATTRIBUTES的指針,用於定義新執行緒的安全屬性,一般設定為NULL。
dwStackSize
分配一直結束表示的執行緒堆疊的大小,其默認值為NULL。
lpStartAddress
指向一個執行緒函式地址,每個執行緒都有自己的執行緒函式,而執行緒函式式執行緒具體執行的代碼。
lpParameter
傳遞給執行緒函式的參數。
dwCreationFlags
表示創建執行緒的運行狀態,其中CREATE_SUSPENDED表示掛起當前創建的執行緒,而0表示立即執行當前創建的執行緒。
lpThreadId
返回新創建執行緒對應的的執行緒ID號。
返回值
返回新創建執行緒對應的的執行緒句柄。
Windows多執行緒同步的C++具體實現代碼#include <tchar.h>#include <windows.h>#include <stdio.h>HANDLE hFile;CRITICAL_SECTION cs; //定義臨界區對象DWORD WINAPI Thread(LPVOID lpParam) //寫檔案執行緒函式{ int n = (int)lpParam; //得到的執行緒 DWORD dwWrite; for (int i=0;i<10000;i++) { //進入臨界區 EnterCriticalSection(&cs); char Data[512]="---------by啊啊啊阿修羅--------- ---------http://314755337.qzone.qq,com---------"; WriteFile(hFile,&Data,strlen(Data),&dwWrite,NULL); //寫入檔案 LeaveCriticalSection(&cs); //出臨界區 } printf("第%d 號執行緒結束運行\n",n); // 輸出執行緒運行結束 return 0;}int _tmain (int argc, char* argv[ ]){ int aaa; hFile=CreateFile(L"C:\\a.text",GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); //創建檔案 if(hFile==INVALID_HANDLE_VALUE) { printf("CreateFile Error\n"); return 0; } DWORD ThreadId; HANDLE hThread[5]; InitializeCriticalSection(&cs);// 初始化臨界區對象 for(int i=0;i<5;i++) //創建5個執行緒   { hThread[i]=CreateThread(NULL,NULL,Thread,LPVOID(i+1),0,&ThreadId); print("第%d 號執行緒創建成功\n",i); } WaitForMultipleObjects(5,hThread,true,INFINITE);//等待5個執行緒運行結束 DeleteCriticalSection(&cs);//刪除臨界區對象 CloseHandle(hFile);//關閉檔案句柄 scanf("%d",&aaa); return 0;}
Linux多執行緒pthread_create函式說明int pthread_create ( pthread_t * thread, const pthread_attr_t * attr, void * (* start_routine) (void *), void * arg);
thread
返回新創建執行緒對應的的執行緒ID號。如果執行緒創建失敗,那么thread指向的值是未定義的。
attr
傳入執行緒屬性
start_routine
指向一個執行緒函式地址,每個執行緒都有自己的執行緒函式,而執行緒函式式執行緒具體執行的代碼。
arg
傳遞給執行緒函式的參數。
返回值
若執行緒創建成功,則返回0。若執行緒創建失敗,則返回錯誤碼。
Linux多執行緒同步的C++具體實現代碼#include <stdio.h>#include <stdlib.h>#include <stdbool.h>#include <pthread.h>#include <unistd.h>#include <semaphore.h>#include <time.h>typedef int COUNT;sem_t p12, p13, p24, p25, p35, p46, p56;int maxLoop[7];void * thread1 ( void * args ){ for ( COUNT i = 0 ; i < maxLoop[1] ; i ++ ) { puts( "I am thread one." ); usleep(500000); } sem_post( &p12 ); sem_post( &p13 ); return NULL;}void * thread2 ( void * args ){ sem_wait( &p12 ); for ( COUNT i = 0 ; i < maxLoop[2] ; i ++ ) { puts( "I am thread two." ); usleep(500000); } sem_post( &p24 ); sem_post( &p25 ); return NULL;}void * thread3 ( void * args ){ sem_wait( &p13 ); for ( COUNT i = 0 ; i < maxLoop[3] ; i ++ ) { puts( "I am thread three." ); usleep(500000); } sem_post( &p35 ); return NULL;}void * thread4 ( void * args ){ sem_wait( &p24 ); for ( COUNT i = 0 ; i < maxLoop[4] ; i ++ ) { puts( "I am thread four." ); usleep(500000); } sem_post( &p46 ); return NULL;}void * thread5 ( void * args ){ sem_wait( &p25 ); sem_wait( &p35 ); for ( COUNT i = 0 ; i < maxLoop[5] ; i ++ ) { puts( "I am thread five." ); usleep(500000); } sem_post( &p56 ); return NULL;}void * thread6 ( void * args ){ sem_wait( &p46 ); sem_wait( &p56 ); for ( COUNT i = 0 ; i < maxLoop[6] ; i ++ ) { puts( "I am thread six." ); usleep(500000); } return NULL;}int main (void){ pthread_t threadid[7]; const int n = 10; srand( time(NULL) ); for ( COUNT i = 1 ; i < 7 ; i ++ ) maxLoop[i] = (rand() % n) + 1; if ( sem_init( &p12, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p13, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p24, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p25, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p35, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p46, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( sem_init( &p56, 0, 0 ) == -1 ) { fprintf( stderr, "Error Initializing Semaphore\n\n"); return EXIT_FAILURE; } if ( pthread_create( &threadid[1], NULL, thread1, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } if ( pthread_create( &threadid[2], NULL, thread2, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } if ( pthread_create( &threadid[3], NULL, thread3, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } if ( pthread_create( &threadid[4], NULL, thread4, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } if ( pthread_create( &threadid[5], NULL, thread5, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } if ( pthread_create( &threadid[6], NULL, thread6, NULL ) ) { fprintf( stderr, "Error Creating Thread.\n\n" ); return EXIT_FAILURE; } for ( COUNT i = 1 ; i < 7 ; i ++ ) { if ( pthread_join( threadid[i] , NULL ) ) { fprintf( stderr, "Error Joining Thread.\n\n" ); return EXIT_FAILURE; } } return 0;}

相關詞條

熱門詞條

聯絡我們