C++多線程同步總結


關於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(&section);//類似於 mutex.lock() 
        cout<<"this is test1 i = "<<i<<endl;
     Sleep(1); LeaveCriticalSection(
&section);//類似於 mutex.unlock() } } void test2() { for(int j=0;j<5;j++) { EnterCriticalSection(&section); cout<<"this is test2 j = "<<j<<endl;
     Sleep(1); LeaveCriticalSection(
&section); } } int main() { InitializeCriticalSection(&section);//初始化臨界區對象 thread a(test1); thread b(test2); a.join(); b.join(); DeleteCriticalSection(&section);//用完了,就刪除臨界區 }

運行結果:

 

 效果類似於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);
}

感覺挺麻煩,都不想多寫了。

 


免責聲明!

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



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