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),然
小白帶你認識netty(三)之NioEventLoop的執行緒(或者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