1. 程式人生 > >C++之多執行緒(POSIX多執行緒例項)

C++之多執行緒(POSIX多執行緒例項)

1.程序同時建立5個執行緒,各自呼叫同一個函式

#include <iostream>
#include <pthread.h> //多執行緒相關操作標頭檔案,可移植眾多平臺
using namespace std;
#define NUM_THREADS 5 //執行緒數
void* say_hello( void* args )
{
    cout << "hello..." << endl;
} //函式返回的是函式指標,便於後面作為引數
int main()
{
    pthread_t tids[NUM_THREADS]; //執行緒id
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        int ret = pthread_create( &tids[i], NULL, say_hello, NULL ); //引數:建立的執行緒id,執行緒引數,執行緒執行函式的起始地址,執行函式的引數
        if( ret != 0 ) //建立執行緒成功返回0
        {
            cout << "pthread_create error:error_code=" << ret << endl;
        }
    }
    pthread_exit( NULL ); //等待各個執行緒退出後,程序才結束,否則程序強制結束,執行緒處於未終止的狀態
}
第一次執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_1【Linux下執行命令】

hello...hello...
hello...
hello...


hello...

第一次執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_1【Linux下執行命令

hello...hello...hello...


hello...
hello...
可知,兩次執行的結果會有差別。

2.執行緒呼叫到函式在一個類中

那必須將該函式宣告為靜態函式,

因為靜態成員函式屬於靜態全域性區,執行緒可以共享這個區域,故可以各自呼叫。

#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
class Hello
{
public:
    static void* say_hello( void* args )
    {
        cout << "hello..." << endl;
    }
};
int main()
{
    pthread_t tids[NUM_THREADS];
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        int ret = pthread_create( &tids[i], NULL, Hello::say_hello, NULL );
        if( ret != 0 )
        {
            cout << "pthread_create error:error_code" << ret << endl;
        }
    }
    pthread_exit( NULL );
}<strong>
</strong>
第一次執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_2

hello...
hello...
hello...
hello...
hello...

第二次執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_2

hello...hello...hello...




hello...
hello...
3.線上程呼叫函式時傳入引數呢
#include <iostream>
#include <pthread.h> //多執行緒相關操作標頭檔案,可移植眾多平臺
using namespace std;
#define NUM_THREADS 5 //執行緒數
void* say_hello( void* args )
{
    int i = *( (int*)args ); //對傳入的引數進行強制型別轉換,由無型別指標轉變為整形指標,再用*讀取其指向到內容
    cout << "hello in " << i <<  endl;
} //函式返回的是函式指標,便於後面作為引數
int main()
{
    pthread_t tids[NUM_THREADS]; //執行緒id
    cout << "hello in main.." << endl;
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        int ret = pthread_create( &tids[i], NULL, say_hello, (void*)&i ); //傳入到引數必須強轉為void*型別,即無型別指標,&i表示取i的地址,即指向i的指標
        cout << "Current pthread id = " << tids[i] << endl; //用tids陣列列印建立的程序id資訊
        if( ret != 0 ) //建立執行緒成功返回0
        {
            cout << "pthread_create error:error_code=" << ret << endl;
        }
    }
    pthread_exit( NULL ); //等待各個執行緒退出後,程序才結束,否則程序強制結束,執行緒處於未終止的狀態
}
顯然不是想要的結果,呼叫順序很亂,這是為什麼呢?

這是因為多執行緒到緣故,主程序還沒開始對i賦值,執行緒已經開始跑了...?

修改程式碼如下:

#include <iostream>
#include <pthread.h> //多執行緒相關操作標頭檔案,可移植眾多平臺
using namespace std;
#define NUM_THREADS 5 //執行緒數
void* say_hello( void* args )
{
    cout << "hello in thread " << *( (int *)args ) <<  endl;
} //函式返回的是函式指標,便於後面作為引數
int main()
{
    pthread_t tids[NUM_THREADS]; //執行緒id
    int indexes[NUM_THREADS]; //用來儲存i的值避免被修改
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        indexes[i] = i;
        int ret = pthread_create( &tids[i], NULL, say_hello, (void*)&(indexes[i]) );
        if( ret != 0 ) //建立執行緒成功返回0
        {
            cout << "pthread_create error:error_code=" << ret << endl;
        }
    }
    for( int i = 0; i < NUM_THREADS; ++i )
        pthread_join( tids[i], NULL ); //pthread_join用來等待一個執行緒的結束,是一個執行緒阻塞的函式
}
執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_3
hello in thread hello in thread hello in thread hello in thread hello in thread 30124

程式碼中如果沒有pthread_join主執行緒會很快結束從而使整個程序結束,從而使建立的執行緒沒有機會開始執行就結束了。加入pthread_join後,主執行緒會一直等待直到等待的執行緒結束自己才結束,使建立的執行緒有機會執行

在此插入join函式簡介:

為什麼要用join()方法:
主執行緒生成並起動了子執行緒,而子執行緒裡要進行大量的耗時的運算(這裡可以借鑑下執行緒的作用),當主執行緒處理完其他的事務後,需要用到子執行緒的處理結果,這個時候就要用到join();方法了。
join方法的作用:
解釋一下,是主執行緒等待子執行緒的終止。也就是在子執行緒呼叫了join()方法後面的程式碼,只有等到子執行緒結束了主執行緒才能執行。(Waits for this thread to die.)

4.執行緒建立時屬性引數的設定pthread_attr_t及join功能的使用

//執行緒的屬性由結構體pthread_attr_t進行管理。
typedef struct
{
    int  detachstate;     執行緒的分離狀態
    int  schedpolicy;   執行緒排程策略
    struct sched_param      schedparam;   執行緒的排程引數
    int inheritsched; 執行緒的繼承性 
    int scope; 執行緒的作用域 
    size_t guardsize; 執行緒棧末尾的警戒緩衝區大小 
    int stackaddr_set; void * stackaddr; 執行緒棧的位置 
    size_t stacksize; 執行緒棧的大小
}pthread_attr_t;
#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
void* say_hello( void* args )
{
    cout << "hello in thread " << *(( int * )args) << endl;
    int status = 10 + *(( int * )args); //執行緒退出時新增退出的資訊,status供主程式提取該執行緒的結束資訊
    pthread_exit( ( void* )status ); 
}
int main()
{
    pthread_t tids[NUM_THREADS];
    int indexes[NUM_THREADS];
    pthread_attr_t attr; //執行緒屬性結構體,建立執行緒時加入的引數
    pthread_attr_init( &attr ); //初始化
    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是設定你想要指定執行緒屬性引數,這個引數表明這個執行緒是可以join連線的,join功能表示主程式可以等執行緒結束後再去做某事,實現了主程式和執行緒同步功能
    for( int i = 0; i < NUM_THREADS; ++i )
    {
        indexes[i] = i;
        int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) );
        if( ret != 0 )
        {
	    cout << "pthread_create error:error_code=" << ret << endl;
	}
    } 
    pthread_attr_destroy( &attr ); //釋放記憶體 
    void *status;
    for( int i = 0; i < NUM_THREADS; ++i )
    {
	int ret = pthread_join( tids[i], &status ); //主程式join每個執行緒後取得每個執行緒的退出資訊status
	if( ret != 0 )
	{
	    cout << "pthread_join error:error_code=" << ret << endl;
	}
	else
	{
	    cout << "pthread_join get status:" << (long)status << endl;
	}
    }
}
執行結果:
[email protected]:~/coding/muti_thread$ ./muti_thread_test_4
hello in thread hello in thread hello in thread hello in thread 0hello in thread 321






4
pthread_join get status:10
pthread_join get status:11
pthread_join get status:12
pthread_join get status:13
pthread_join get status:14

5.互斥鎖的實現

互斥鎖是實現執行緒同步的一種機制,只要在臨界區前後對資源加鎖就能阻塞其他程序的訪問。

#include <iostream>
#include <pthread.h>
using namespace std;
#define NUM_THREADS 5
int sum = 0; //定義全域性變數,讓所有執行緒同時寫,這樣就需要鎖機制
pthread_mutex_t sum_mutex; //互斥鎖
void* say_hello( void* args )
{
    cout << "hello in thread " << *(( int * )args) << endl;
    pthread_mutex_lock( &sum_mutex ); //先加鎖,再修改sum的值,鎖被佔用就阻塞,直到拿到鎖再修改sum;
    cout << "before sum is " << sum << " in thread " << *( ( int* )args ) << endl;
    sum += *( ( int* )args );
    cout << "after sum is " << sum << " in thread " << *( ( int* )args ) << endl;
    pthread_mutex_unlock( &sum_mutex ); //釋放鎖,供其他執行緒使用
    pthread_exit( 0 ); 
}
int main()
{
    pthread_t tids[NUM_THREADS];
    int indexes[NUM_THREADS];
    pthread_attr_t attr; //執行緒屬性結構體,建立執行緒時加入的引數
    pthread_attr_init( &attr ); //初始化
    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是設定你想要指定執行緒屬性引數,這個引數表明這個執行緒是可以join連線的,join功能表示主程式可以等執行緒結束後再去做某事,實現了主程式和執行緒同步功能
    pthread_mutex_init( &sum_mutex, NULL ); //對鎖進行初始化    

    for( int i = 0; i < NUM_THREADS; ++i )
    {
        indexes[i] = i;
        int ret = pthread_create( &tids[i], &attr, say_hello, ( void* )&( indexes[i] ) ); //5個程序同時去修改sum
        if( ret != 0 )
        {
	    cout << "pthread_create error:error_code=" << ret << endl;
	}
    } 
    pthread_attr_destroy( &attr ); //釋放記憶體 
    void *status;
    for( int i = 0; i < NUM_THREADS; ++i )
    {
	int ret = pthread_join( tids[i], &status ); //主程式join每個執行緒後取得每個執行緒的退出資訊status
	if( ret != 0 )
	{
	    cout << "pthread_join error:error_code=" << ret << endl;
	}
    }
    cout << "finally sum is " << sum << endl;
    pthread_mutex_destroy( &sum_mutex ); //登出鎖
}
執行結果:

[email protected]:~/coding/muti_thread$ ./muti_thread_test_5

hello in thread hello in thread hello in thread 410
before sum is hello in thread 0 in thread 4
after sum is 4 in thread 4hello in thread 


2
3
before sum is 4 in thread 1
after sum is 5 in thread 1
before sum is 5 in thread 0
after sum is 5 in thread 0
before sum is 5 in thread 2
after sum is 7 in thread 2
before sum is 7 in thread 3
after sum is 10 in thread 3
finally sum is 10
可知,sum的訪問和修改順序是正常的,這就達到了多執行緒的目的了,但是執行緒的執行順序是混亂的,混亂就是正常?
6.訊號量的實現

訊號量是執行緒同步的另一種實現機制,訊號量的操作有signal和wait,本例子採用條件訊號變數pthread_cond_t tasks_cond;
訊號量的實現也要給予鎖機制。

#include <iostream>
#include <pthread.h>
#include <stdio.h>
using namespace std;
#define BOUNDARY 5
int tasks = 10;
pthread_mutex_t tasks_mutex; //互斥鎖
pthread_cond_t tasks_cond; //條件訊號變數,處理兩個執行緒間的條件關係,當task>5,hello2處理,反之hello1處理,直到task減為0

void* say_hello2( void* args )
{
    pthread_t pid = pthread_self(); //獲取當前執行緒id
    cout << "[" << pid << "] hello in thread " <<  *( ( int* )args ) << endl;
    
    bool is_signaled = false; //sign
    while(1)
    {
	pthread_mutex_lock( &tasks_mutex ); //加鎖
	if( tasks > BOUNDARY )
	{
	    cout << "[" << pid << "] take task: " << tasks << " in thread " << *( (int*)args ) << endl;
 	    --tasks; //modify
	}
	else if( !is_signaled )
	{
	    cout << "[" << pid << "] pthread_cond_signal in thread " << *( ( int* )args ) << endl;
	    pthread_cond_signal( &tasks_cond ); //signal:向hello1傳送訊號,表明已經>5
	    is_signaled = true; //表明訊號已傳送,退出此執行緒
	}
	pthread_mutex_unlock( &tasks_mutex ); //解鎖
	if( tasks == 0 )
	    break;
    }    
}

void* say_hello1( void* args )
{
    pthread_t pid = pthread_self(); //獲取當前執行緒id
    cout << "[" << pid << "] hello in thread " <<  *( ( int* )args ) << endl;

    while(1)
    {
        pthread_mutex_lock( &tasks_mutex ); //加鎖
        if( tasks > BOUNDARY )
        {
	    cout << "[" << pid << "] pthread_cond_signal in thread " << *( ( int* )args ) << endl;
	    pthread_cond_wait( &tasks_cond, &tasks_mutex ); //wait:等待訊號量生效,接收到訊號,向hello2發出訊號,跳出wait,執行後續 
        }
        else
        {
	    cout << "[" << pid << "] take task: " << tasks << " in thread " << *( (int*)args ) << endl;
            --tasks;
	}
        pthread_mutex_unlock( &tasks_mutex ); //解鎖
        if( tasks == 0 )
            break;
    } 
}


int main()
{
    pthread_attr_t attr; //執行緒屬性結構體,建立執行緒時加入的引數
    pthread_attr_init( &attr ); //初始化
    pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); //是設定你想要指定執行緒屬性引數,這個引數表明這個執行緒是可以join連線的,join功能表示主程式可以等執行緒結束後再去做某事,實現了主程式和執行緒同步功能
    pthread_cond_init( &tasks_cond, NULL ); //初始化條件訊號量
    pthread_mutex_init( &tasks_mutex, NULL ); //初始化互斥量
    pthread_t tid1, tid2; //儲存兩個執行緒id
    int index1 = 1;
    int ret = pthread_create( &tid1, &attr, say_hello1, ( void* )&index1 );
    if( ret != 0 )
    {
        cout << "pthread_create error:error_code=" << ret << endl;
    }
    int index2 = 2;
    ret = pthread_create( &tid2, &attr, say_hello2, ( void* )&index2 );
    if( ret != 0 )
    {
        cout << "pthread_create error:error_code=" << ret << endl;
    }
    pthread_join( tid1, NULL ); //連線兩個執行緒
    pthread_join( tid2, NULL ); 

    pthread_attr_destroy( &attr ); //釋放記憶體 
    pthread_mutex_destroy( &tasks_mutex ); //登出鎖
    pthread_cond_destroy( &tasks_cond ); //正常退出
}
測試結果:
先線上程2中執行say_hello2,再跳轉到執行緒1中執行say_hello1,直到tasks減到0為止。

[email protected]:~/coding/muti_thread$ ./muti_thread_test_6  

[3069823856] hello in thread 2
[3078216560] hello in thread 1[3069823856] take task: 10 in thread 2

[3069823856] take task: 9 in thread 2
[3069823856] take task: 8 in thread 2
[3069823856] take task: 7 in thread 2
[3069823856] take task: 6 in thread 2
[3069823856] pthread_cond_signal in thread 2
[3078216560] take task: 5 in thread 1
[3078216560] take task: 4 in thread 1
[3078216560] take task: 3 in thread 1
[3078216560] take task: 2 in thread 1
[3078216560] take task: 1 in thread 1





相關推薦

C++執行POSIX執行例項

1.程序同時建立5個執行緒,各自呼叫同一個函式 #include <iostream> #include <pthread.h> //多執行緒相關操作標頭檔案,可移植眾多平臺 using namespace std; #define NUM_TH

Python實戰執行函式執行,類執行,守護執行,GIL,執行lock,遞迴Rlock,Semaphore訊號量,event

首先須知 什麼是IO? 從硬碟讀塊資料,從網路讀塊資料屬於IO操作(IO操作不佔用cpu) 計算佔用cpu,如:1+1 Python多執行緒其實就是一個執行緒,由於利用CUP的上下文切換看起來就像是併發..上下文切換消耗資源 Python多執行緒 不適合CPU密集操作型的任務,適

自己實戰整理面試題--執行帶答案,不斷更新

一個執行緒兩次呼叫 start() 方法會出現什麼情況?執行緒的生命週期,狀態是如何轉移的? Java 的執行緒是不允許啟動兩次的,第二次呼叫必然會丟擲 IllegalThreadStateException,這是一種執行時異常,多次呼叫 start 被認為是程式設計錯誤。 關於執行緒生

利用執行用到原子類AtomicInteger往資料庫批量插入大量資料

package duocharu; import com.minisay.base.util.OJDBCUtils; import java.sql.Connection; import java.sql.PreparedStatement; import

Java的執行Java基礎複習歸納系列

目錄 1.程序 2.執行緒 一、執行緒概述 1.程序 在一個作業系統中,每個獨立執行的程式都可稱之為一個程序,也就是“正在執行的程式”。 程序和程式 A  proce

初見Java執行三、執行的阻塞狀態

1. 阻止執行緒執行 對於執行緒的阻塞狀態,考慮一下三個方面,不考慮IO阻塞的情況: 睡眠; 等待; 因為需要一個物件的鎖定而被阻塞。 2. 睡眠 Thread.sleep(long millis); Thread.sleep(long mill

這個秋季過關斬將—設計模式,分散式,執行文末有彩蛋

一、前言 今天為什麼要談論這個話題暱?想必大家都知道了,又到一年的中跳槽季了,肯定有一些小夥伴寂寞難耐,想出去搞事情了。在此,我丟擲三個詞,這三詞應該歸屬面試最熱詞的範疇了,這是我自身體會及從各個同行公認的。下面我簡單概述一下,希望對大夥有所幫助。 二、設計模式 概念 設計模式(Design Patt

Selenium_python自動化跨瀏覽器執行測試簡單線程案例

思路 IT port 情況 art 百度一 吸引 find 導致 發生背景:     跨瀏覽器測試是功能測試的一個分支,用以驗證web應用在不同瀏覽器上的正常工作,通常情況下,我們都期望web類應用能夠被我們的用戶在任何瀏覽器上使用,例如有的人喜歡IE瀏覽器上使用,有的人喜

python學習網站的編寫HTML,CSS,JS----------CSS中用的最的class選擇器,批量的為一些標籤設定相同的版式

選擇器有很多種,有id選擇器,div選擇器,層級選擇器,組合選擇器等等,然而,用的最多的就是class選擇器,它的作用是為下面所有符合class規則的標籤設定上相同的版式。 步驟: 1.在頭部編寫<style>標籤,點+class選擇器的名稱(也就是下面需要選擇的class),然

小白帶你認識nettyNioEventLoop的執行或者reactor執行啟動

在上一章中,我們看了處理IO事件的過程,今天,我們瞅瞅處理非同步任務佇列。 3、處理非同步任務佇列 在執行完processSelectedKeys方法後,netty會繼續執行runAllTasks方法,在觀摩這個方法之前,我們瞭解下netty的task。 在初始化NioEventLoop的時候,會例

根據cron表示式計算每天的執行時刻可能

         我們專案中一般會有很多的定時任務,我們怎麼知道這些定時任務是否正常執行了呢?一個基本的想法是,在任務執行前儲存一條記錄,任務執行後更新此記錄的結束時間和標記,異常的時候記錄失敗標記和異常資訊,然後管理員每天登入的時候檢查每個任務是否正常執行。如果記錄與設定的

C# 帶附件郵件傳送支援附件

工作需要用到了多附件傳送功能,現在貼出來,有需要的共享一下。 //帶附件傳送,支援多個附件        public bool sendMailFile(string from, string to, string subject, string body,string

HQL表查詢一對

https://www.cnblogs.com/kingxiaozi/p/6020956.html原作者一、一對多以班級Classes和學生Student為例:回憶sql語句://內連結,兩種方式效果一樣,查詢的是兩邊都有的資料SELECT c.*,s.* FROM clas

Gradle 編譯個project包括Library庫project依賴指導

pil 出現 基於 viewpage eclips support class 什麽 cor Gradle Android最新自己主動化編譯腳本教程(提供demo源代碼)這篇文章我簡單寫了基於Gradle2.1 進行的android project和android lib

C變量屬性

C語言 auto static register extern 我們知道以在 C 語言中的變量有自己的屬性,只要在定義變量的時候加上“屬性”關鍵字即可。“屬性”關鍵字指明變量的特有意義。 語法:property type var_name;比如:auto in

C goto 和 void

C語言 goto void 我們在 C 語言中經常會見到 void ,也會偶爾見到 goto。那麽 C 語言中既然有 goto ,為什麽我們在代碼中見的很少呢?在以前很多的項目經驗中,我們得到這樣一條潛規則:一般項目都是禁用 goto 的,程序質量與 goto 的出現次數成反比。自

C const 和 volatile

C語言 const volatile 在 C 語言中,我們經常會見到 const 和 volatile 這兩個關鍵字,那麽我們今天就來介紹下這兩個關鍵字。 先來介紹 const 關鍵字。提起 const 關鍵字,我們可能首先想到的是經過它修飾的變量便是常量了。其實我

C struct 和 union

C語言 struct union 在 C 語言中我們經常會使用到 struct 和 union,那麽它們兩個各自有何特點呢?今天我們就一探究竟。 我們先來介紹下 struct 。它可以看做是變量的集合,那麽一個空的結構體占多大內存呢?這是一個有趣的問題,按照理論分析,

C邏輯運算符十四

C語言 && || ! 我們在 C 語言中經常會遇到邏輯運算符。|| 是從左向右開始計算的,當遇到為真的條件時停止計算,整個表達式為真;所有條件為假時表達式才為假。 && 是從左向右開始計算,當遇到為假的條件時停止計算,整個表達式為假;所有條件為真時表達式才為真

C #error 和 #line二十一

C語言 #error #line 我們今天來講下 C 語言中的兩個比較偏僻的知識點,之所以說偏僻是因為在平時的代碼中我們見得很少。首先來說下 #error,它是用於生成一個編譯錯誤消息。用法如下:#error message;註意 message 不需要用雙引號包圍。#error