關於C++多線程,寫得好的博客太多了,內容豐富,排版又好看,就是難找。
整體看過以后,本人也總結一下,僅作為日后參照。
這里先推薦看過的幾篇博文鏈接,非常值得一看。
https://blog.csdn.net/dingdingdodo/article/details/108477195
https://www.cnblogs.com/yinbiao/p/11190336.html
http://zhangxiaoya.github.io/2015/05/15/multi-thread-of-c-program-language-on-linux/
https://www.cnblogs.com/hesper/p/10738987.html
https://blog.csdn.net/qq_39382769/article/details/96075346
注:本人所用IDE為Dev-C++。
重在簡潔啊,而且既能用windows平台下的,也能用linux平台下的多線程機制。
一:C++11規范下的線程庫
1.C++11 線程庫的基本用法:創建線程、分離線程
#include<iostream> #include<thread> #include<windows.h> using namespace std; void threadProc() { cout<<"this is in threadProc\n"; cout<<"thread1's id is "<<this_thread::get_id()<<endl; //獲取所屬線程的id } void threadProc2(int num) { cout<<"thread num = "<<num<<endl; } void threadProc3() { cout<<"this thread is detached\n"; } void threadProc4() { cout<<"this thread is detached and won't print in the same console.'\n"; } int main() { thread a;//創建線程1,定義線程,后面再分配任務 a = thread(threadProc); thread b(threadProc2,5);//創建線程2 ,定義線程的時候分配任務,參數類似於printf一樣,可以為多個 a.join(); b.join();//采用join,主線程會阻塞等待子線程執行完畢 thread c(threadProc3); c.detach();//采用detach,主線程不會等,這個線程開啟早,還能輸出到主線程的控制台 cout<<"main thread exit"<<endl; thread d(threadProc4); d.detach();//這個線程太晚了,主線程已經結束,不能輸出到主線程的控制台了 }
運行結果:
2.基本的互斥鎖
上述運行,輸出語句顯然沒有順序執行,為了達到一行一行輸出的效果,可以使用最基本的互斥鎖。
#include<iostream> #include<thread> #include<mutex> using namespace std; mutex mu;//互斥鎖 void test1() { for(int i=0;i<5;i++) { // mu.lock();//鎖住 cout<<"test1 i = "<<i<<endl; // mu.unlock();//釋放 } } void test2() { for(int j=0;j<5;j++) { // mu.lock(); cout<<"test2 j = "<<j<<endl; // mu.unlock(); } } int main() { thread a(test1); thread b(test2); a.join(); b.join(); cout<<"main thread finish."<<endl; }
運行結果1:
不加鎖的話,輸出就會混亂。
這里打開4行注釋,重新運行。
運行結果2:
可以簡單理解為,test1獲得鎖以后,test2調用lock(),就會阻塞執行,直到test1()調用unlock()釋放鎖。
3.lock_guard.
#include<iostream> #include<thread> #include<mutex> using namespace std; mutex mu;//互斥鎖 /* lock_guard<mutex> locka(mu); 作用范圍為從這一行開始,到那一次循環結束,還不用自己手動解鎖。 */ void test1() { for(int i=0;i<5;i++) { lock_guard<mutex> locka(mu); cout<<"test1 i = "<<i<<endl; } } void test2() { for(int j=0;j<5;j++) { lock_guard<mutex> lock(mu); cout<<"test2 j = "<<j<<endl; } } int main() { thread a(test1); thread b(test2); a.join(); b.join(); cout<<"main thread finish."<<endl; }
運行結果:
4.unique_lock
#include<iostream> #include<thread> #include<mutex> using namespace std; mutex mu;//互斥鎖 void test1() { for(int i=0;i<5;i++) { unique_lock<mutex> locka(mu,defer_lock); cout<<"test1 i = "<<i<<endl; locka.lock(); cout<<"this is lock1"<<endl; } } void test2() { for(int j=0;j<5;j++) { unique_lock<mutex> locka(mu); cout<<"test2 j = "<<j<<endl; locka.unlock(); locka.lock(); cout<<"this is lock2"<<endl; } } int main() { thread a(test1); thread b(test2); a.join(); b.join(); cout<<"main thread finish."<<endl; }
運行結果:
5.condition_variable
#include<iostream> #include<thread> #include<mutex> #include<condition_variable> using namespace std; mutex mu; condition_variable cv; bool print = false; void test1() { for(int i=0;i<5;i++) { unique_lock<mutex> l(mu); cout<<"test1 i = "<<i<<endl; cv.notify_one(); print = true; } } void test2() { for(int j=0;j<5;j++) { unique_lock<mutex> l(mu); if(!print) { cv.wait(l); } cout<<"test2 j = "<<j<<endl; print = false; } } int main() { thread a(test1); thread b(test2); a.join(); b.join(); }
運行結果如下:
二:W32API實現線程同步
1.臨界區
#include<iostream> #include<thread> #include<windows.h> using namespace std; CRITICAL_SECTION section;//臨界區變量 void test1() { for(int i=0;i<5;i++) { EnterCriticalSection(§ion);//類似於 mutex.lock() cout<<"this is test1 i = "<<i<<endl;
Sleep(1); LeaveCriticalSection(§ion);//類似於 mutex.unlock() } } void test2() { for(int j=0;j<5;j++) { EnterCriticalSection(§ion); cout<<"this is test2 j = "<<j<<endl;
Sleep(1); LeaveCriticalSection(§ion); } } int main() { InitializeCriticalSection(§ion);//初始化臨界區對象 thread a(test1); thread b(test2); a.join(); b.join(); DeleteCriticalSection(§ion);//用完了,就刪除臨界區 }
運行結果:
效果類似於mutex,只是都要在執行完循環進行解鎖的操作
2.互斥鎖。
#include<iostream> #include<thread> #include<windows.h> using namespace std; HANDLE hmutex; void test1() { for(int i=0;i<5;i++) { WaitForSingleObject(hmutex,INFINITE);//類似於mutex.lock() 阻塞等待多少時間 cout<<"test1 i = "<<i<<endl; ReleaseMutex(hmutex);//類似於mutex.unlock() 釋放互斥鎖 } } void test2() { for(int j=0;j<5;j++) { WaitForSingleObject(hmutex,INFINITE); cout<<"test2 j = "<<j<<endl; ReleaseMutex(hmutex); } } int main() { hmutex = CreateMutex(NULL,FALSE,"mutex");//創建一個互斥鎖 thread a(test1); thread b(test2); a.join(); b.join(); CloseHandle(hmutex);//釋放句柄 }
運行結果:
效果基本差不多的,讓輸出有順序是綽綽有余了。
3.事件
#include<iostream> #include<thread> #include<windows.h> using namespace std; HANDLE hevent; void test1() { for(int i=0;i<5;i++) { WaitForSingleObject(hevent,INFINITE);//類似於mutex.lock() 阻塞等待多少時間 cout<<"test1 i = "<<i<<endl; SetEvent(hevent);//類似於mutex.unlock() 釋放互斥鎖 } } void test2() { for(int j=0;j<5;j++) { WaitForSingleObject(hevent,INFINITE); cout<<"test2 j = "<<j<<endl; SetEvent(hevent); } } int main() { hevent = CreateEvent(NULL,FALSE,TRUE,"event");//創建一個事件 thread a(test1); thread b(test2); a.join(); b.join(); CloseHandle(hevent);//釋放句柄 }
運行結果:
4.信號量
#include<iostream> #include<thread> #include<windows.h> using namespace std; HANDLE sem; void test1() { for(int i=0;i<5;i++) { WaitForSingleObject(sem,INFINITE);//類似於mutex.lock() 阻塞等待多少時間 cout<<"test1 i = "<<i<<endl; ReleaseSemaphore(sem,1,NULL);//類似於mutex.unlock() 釋放互斥鎖 } } void test2() { for(int j=0;j<5;j++) { WaitForSingleObject(sem,INFINITE); cout<<"test2 j = "<<j<<endl; ReleaseSemaphore(sem,1,NULL); } } int main() { sem = CreateSemaphore(NULL,1,2,"semaphore"); thread a(test1); thread b(test2); a.join(); b.join(); CloseHandle(sem);//釋放句柄 }
運行結果:
三:linux支持的多線程同步
1.互斥鎖
#include<iostream> #include<thread> #include<pthread.h> using namespace std; pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; void test1() { for(int i=0;i<5;i++) { pthread_mutex_lock(&mu);//類似於mutex.lock() 阻塞等待多少時間 cout<<"test1 i = "<<i<<endl; pthread_mutex_unlock(&mu);//類似於mutex.unlock() 釋放互斥鎖 } } void test2() { for(int j=0;j<5;j++) { pthread_mutex_lock(&mu); cout<<"test2 j = "<<j<<endl; pthread_mutex_unlock(&mu); } } int main() { thread a(test1); thread b(test2); a.join(); b.join(); }
2.條件變量
#include<iostream> #include<thread> #include<pthread.h> using namespace std; pthread_mutex_t mu = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; bool one = true; void test1() { pthread_mutex_lock(&mu); cout<<"test1 begin()"<<endl; while(one) { pthread_cond_wait(&cond,&mu); } cout<<"test1 continue"<<endl; pthread_mutex_unlock(&mu); } void test2() { pthread_mutex_lock(&mu); cout<<"test2 begin()"<<endl; one = false; pthread_mutex_unlock(&mu); cout<<"test2 finish"<<endl; pthread_cond_signal(&cond); } int main() { thread a(test1); thread b(test2); a.join(); b.join(); }
運行結果:
3.信號量
#include<iostream> #include<pthread.h> #include<semaphore.h> #include<thread> using namespace std; sem_t se; void test1() { for(int i=0;i<5;i++) { sem_wait(&se);//類似於mutex.lock() 阻塞等待多少時間 cout<<"test1 i = "<<i<<endl; sem_post(&se);//類似於mutex.unlock() 釋放互斥鎖 } } void test2() { for(int j=0;j<5;j++) { sem_wait(&se);; cout<<"test2 j = "<<j<<endl; sem_post(&se); } } int main() { sem_init(&se,0,1);//初始化信號量 thread a(test1); thread b(test2); a.join(); b.join(); sem_destroy(&se);//刪除信號量 }
4.讀寫鎖
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <pthread.h> int number = 0; // 讀寫鎖 pthread_rwlock_t lock; void *write_func(void *arg) { while (1) { pthread_rwlock_wrlock(&lock); number++; printf("+++++write: %lu, %d\n", pthread_self(), number); pthread_rwlock_unlock(&lock); sleep(1); } return NULL; } void *read_func(void *arg) { while (1) { pthread_rwlock_rdlock(&lock); printf("======read: %lu, %d\n", pthread_self(), number); pthread_rwlock_unlock(&lock); sleep(1); } return NULL; } int main() { int i; pthread_t p[8]; // 初始化讀寫鎖 pthread_rwlock_init(&lock, NULL); // 3個寫線程 for (i = 0; i < 3; i++) { pthread_create(&p[i], NULL, write_func, NULL); } // 5個讀線程 for (i = 3; i < 8; i++) { pthread_create(&p[i], NULL, read_func, NULL); } // 回收子線程 for (i = 0; i < 8; i++) { pthread_join(p[i], NULL); } pthread_rwlock_destroy(&lock); return 0; }
這一篇直接使用別人的代碼了,麻煩,直接作為參考就好了。
5.不使用C++11線程庫創建線程
#include<iostream> #include<pthread.h> using namespace std; void* test1(void*) { cout<<"hello world"<<endl; } int main() { pthread_t t1; pthread_create(&t1,NULL,test1,NULL); pthread_join(t1,NULL); }
感覺挺麻煩,都不想多寫了。