C++的線程管理

C++的線程管理

  • 線程類(Thread)
    • 線程構造器
      • 約定構造器
      • 初始化構造器
      • 復制構造器
      • 移動構造器
  • 多線程
    • atomic
    • condition_variable
      • 應用實列
    • future
      • promise
        • 應用實列
      • future
        • 應用實列

線程類(Thread)

執行線程是一個指令序列,它可以在多線程環境中,與其他此類指令序列同時執行,同時共享相同的地址空間。

一個初始化的線程對象代表一個活動的執行線程;這樣的線程對象是可連接的,并且具有唯一的線程ID。

默認構造的(未初始化的)線程對象是不可連接的,并且它的線程 id 對于所有不可連接的線程都是通用的。

如果從可連接線程移出,或者對它們調用 join 或 detach,則該線程將變得不可連接。

#include <iostream>
#include <thread>
#include <unistd.h>using namespace std;void foo() 
{sleep(10);  //  sleep 10 secondscout << "I'm foo, awake now" << endl;
}void bar(int x)
{sleep(5);  //  sleep 10 secondscout << "I'm bar, awake now" << endl;
}int main() 
{thread T1 (foo);     // spawn new thread that calls foo()thread T2 (bar,0);  // spawn new thread that calls bar(0)cout << "main, foo and bar now execute concurrently...\n";// synchronize threads:T1.join();                // pauses until first finishesT2.join();               // pauses until second finishescout << "foo and bar completed.\n";return 0;
}

程序運行屏幕輸出

main, foo and bar now execute concurrently...
I'm bar, awake now
I'm foo, awake now
foo and bar completed.

線程構造器

- thread() noexcept;- template <class Fn, class... Args>explicit thread (Fn&& fn, Args&&... args); - thread (const thread&) = delete; - thread (thread&& x) noexcept;

約定構造器

thread() noexcept;

構造一個線程對象, 它不包含任何執行線程。

初始化構造器

template <class Fn, class... Args>explicit thread (Fn&& fn, Args&&... args);

構造一個線程對象,它擁有一個可連接執行線程。
新的執行線程調用 fn, 并傳遞 args 作為參數。
此構造的完成與 fn 的副本開始運行同步。

#include <chrono>
#include <iostream>
#include <thread>
#include <utility>using namespace std;void f1(int n)
{for (int i = 0; i < 5; ++i){cout << "Thread 1 executing\n";++n;this_thread::sleep_for(chrono::milliseconds(10));}
}void f2(int& n, int sz)
{for (int i = 0; i < sz; ++i){cout << "Thread 2 executing\n";++n;this_thread::sleep_for(chrono::milliseconds(10));}
}int main()
{int n = 0;thread t2(f1, n + 1); 		 // pass by valuethread t3(f2, ref(n), 6); // pass by referencet2.join();t3.join();cout << "Final value of n is " << n << '\n';
}

程序運行屏幕輸出

Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 2 executing
Thread 1 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 2 executing
Final value of n is 6

復制構造器

thread (const thread&) = delete; 

刪除構造函數,線程對象不能復制。

移動構造器

thread (thread&& x) noexcept;

構造一個線程對象,該對象獲取 x 表示的執行線程(如果有)。此操作不會以任何方式影響移動線程的執行,它只是傳輸其處理程序。
x 對象不再代表任何執行線程。

#include <chrono>
#include <iostream>
#include <thread>
#include <utility>
#include <unistd.h>using namespace std;void f2(int& n)
{thread::id this_id = this_thread::get_id();cout << "Thread " << this_id << " executing" << endl;for (int i = 0; i < 5; ++i){++n;this_thread::sleep_for(std::chrono::milliseconds(10));}
}int main()
{int n = 0;thread t3(f2, ref(n));thread t4(move(t3));t4.join();cout << "Final value of n is " << n << '\n';
}

程序運行屏幕輸出

Thread 140291256411904 executing
Final value of n is 5

多線程

atomic

atomic類型是封裝值的類型,保證其訪問不會導致數據爭用,并且可用于同步不同線程之間的內存訪問。

#include <iostream>
#include <atomic>
#include <thread>
#include <vector>
#include <random>using namespace std;atomic<bool> ready (false);
atomic_flag winner = ATOMIC_FLAG_INIT;void count1m (int id) {random_device dev;mt19937 rng(dev());uniform_int_distribution<mt19937::result_type> dist6(50,100); // distribution in range [1, 6]while (!ready) { this_thread::yield(); }int val = dist6(rng);	this_thread::sleep_for(chrono::milliseconds(val));if (!winner.test_and_set()) { cout << "thread #" << id << " won!\n"; }
}int main ()
{vector<thread> threads;cout << "5 threads compete...\n";for (int i=1; i<=5; ++i) threads.push_back(thread(count1m,i));ready = true;for (auto& th : threads) th.join();return 0;
}

程序運行2次,屏幕輸出

threads$ ./atomic
5 threads compete...
thread #3 won!
threads$ ./atomic
5 threads compete...
thread #4 won!

condition_variable

條件變量是一個能夠阻塞調用線程,直到通知恢復的對象。

當調用其等待函數之一時,它使用 unique_lock(通過互斥鎖)來鎖定線程。該線程將保持阻塞狀態,直到被另一個對同一 condition_variable 對象調用通知函數的線程喚醒。

Condition_variable 類型的對象始終使用 unique_lock 進行等待。

應用實列

#include <iostream>
#include <thread>
#include <mutex>
#include <vector>
#include <condition_variable>using namespace std;mutex mtx;
condition_variable cv;
bool ready = false;void wait_init_ready (int id) {unique_lock<mutex> lck(mtx);cout << "Init " << id << " start ..." << endl;while (!ready) cv.wait(lck);cout << "Init " << id << " done !!!" << '\n';
}void init_complete() {unique_lock<mutex> lck(mtx);ready = true;cv.notify_all();
}int main ()
{vector<thread> threads;for (int i=0; i<5; ++i)threads.push_back(thread(wait_init_ready, i));init_complete();for (auto& th : threads) th.join();return 0;
}

程序運行屏幕輸出

Init 0 start ...
Init 1 start ...
Init 3 start ...
Init 3 done !!!
Init 1 done !!!
Init 4 start ...
Init 4 done !!!
Init 0 done !!!
Init 2 start ...
Init 2 done !!!

future

具有允許異步訪問特定提供程序(可能在不同線程中)設置的值的功能的標頭。

這些提供者中的每一個(要么是promise或packaged_task對象,要么是對async的調用)與未來對象共享對共享狀態的訪問:提供者使共享狀態準備就緒的點與未來對象訪問共享狀態的點同步狀態。

promise

Promise 是一個對象,它可以存儲類型 T 的值,以便將來的對象(可能在另一個線程中)檢索,從而提供同步點。

在構造時,Promise 對象與一個新的共享狀態相關聯,它們可以在該狀態上存儲類型 T 的值或從 std::exception 派生的異常。

通過調用成員 get_future,可以將該共享狀態關聯到未來對象。調用后,兩個對象共享相同的共享狀態:

  • Promise 對象是異步提供者,預計會在某個時刻為共享狀態設置一個值。
  • future 對象是一個異步返回對象,可以檢索共享狀態的值,并在必要時等待它準備好。

共享狀態的生命周期至少持續到與其關聯的最后一個對象釋放它或被銷毀為止。因此,如果也與 future 相關聯,它可以在最初獲得它的 Promise 對象中存活下來。

應用實列
#include <iostream>
#include <functional>
#include <thread>
#include <future>using namespace std;struct data_pkt {int  id;uint8_t  data[20];
};void wait_new_value (future<data_pkt>& fut) {data_pkt x = fut.get();cout << "value: " << x.id << '\n';
}int main ()
{data_pkt  pkt;promise<data_pkt> prom;                      // create promisefuture<data_pkt> fut = prom.get_future();    // engagement with futurethread th1 (wait_new_value, ref(fut));  		// send future to new threadpkt.id = 1;prom.set_value (pkt);                        // fulfill promise// (synchronizes with getting the future)th1.join();return 0;
}

程序運行屏幕輸出

value: 1

future

future 是一個可以從某些提供程序對象或函數檢索值的對象,如果在不同的線程中,則可以正確同步此訪問。

“有效”未來是與共享狀態關聯的未來對象,并通過調用以下函數之一來構造:
異步
承諾::get_future
打包任務::獲取未來

future 對象僅在有效時才有用。默認構造的未來對象無效(除非移動分配了有效的未來)。

在有效的 future 上調用 future::get 會阻塞線程,直到提供者使共享狀態準備就緒(通過設置值或異常)。這樣,兩個線程可以通過一個等待另一個線程設置值來同步。

共享狀態的生命周期至少持續到與其關聯的最后一個對象釋放它或被銷毀為止。因此,如果與未來相關聯,共享狀態可以在最初獲取它的對象(如果有)中繼續存在。

應用實列
#include <iostream>
#include <future>
#include <chrono>
#include <signal.h>using namespace std;bool ready = false;
mutex mtx;
condition_variable cv;struct data_pkt {int   code;uint8_t  data[32];
};void term(int signum)
{if (signum == SIGINT){   printf("Received SIGINT(ctrl+c), exiting ... \n");unique_lock<mutex> lck(mtx);ready = true;cv.notify_all();}else{time_t mytime = time(0);printf("%d: %s\n", signum, asctime(localtime(&mytime)));printf("%d\n",signum);}
}bool async_promise (data_pkt &pkt) {cout << "async_promise start ..." << endl;struct sigaction act;act.sa_handler = term;sigaction(SIGQUIT, &act, NULL);sigaction(SIGINT, &act, NULL);unique_lock<mutex> lck(mtx);  while (!ready) cv.wait(lck);cout << "async_promise condition variable ready" << endl;	pkt.code = 1900;return true;
}int main ()
{data_pkt  pkt;// call function asynchronously:future<bool> fut = async (async_promise, ref(pkt)); // do something while waiting for function to set future:cout << "checking, please wait";chrono::milliseconds span (100);while (fut.wait_for(span) == future_status::timeout)cout << '.' << flush;bool x = fut.get();     // retrieve return valuecout << pkt.code << endl;return 0;
}
checking, please waitasync_promise start ...
............................^CReceived SIGINT(ctrl+c), exiting ...
async_promise condition variable ready
1900

函數模板 std::async 異步運行函數 f ,可能在一個單獨的線程中,該線程可能是線程池的一部分,并返回一個 std::future ,它最終將保存該函數調用的結果。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/44464.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/44464.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/44464.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Canvas:實現在線畫板操作

想象一下&#xff0c;用幾行代碼就能創造出如此逼真的圖像和動畫&#xff0c;仿佛將藝術與科技完美融合&#xff0c;前端開發的Canvas技術正是這個數字化時代中最具魔力的一環&#xff0c;它不僅僅是網頁的一部分&#xff0c;更是一個無限創意的畫布&#xff0c;一個讓你的想象…

python網絡爬蟲之Urllib

概述 urllib的request模塊提供了最基本的構造HTTP請求的方法&#xff0c;使用它可以方便地實現請求的發送并得到響應&#xff0c;同時它還帶有處理授權驗證&#xff08;authentication&#xff09;、重定向&#xff08;redirection&#xff09;、瀏覽器Cookies以及其他內容。 …

DELTA: DEGRADATION-FREE FULLY TEST-TIME ADAPTATION--論文筆記

論文筆記 資料 1.代碼地址 2.論文地址 https://arxiv.org/abs/2301.13018 3.數據集地址 https://github.com/bwbwzhao/DELTA 論文摘要的翻譯 完全測試時間自適應旨在使預訓練模型在實時推理過程中適應測試數據流&#xff0c;當測試數據分布與訓練數據分布不同時&#x…

算法中的基礎知識點,你知道多少呢!

遞歸 場景&#xff1a; ? 1&#xff09;斐波那契數列 遞推 場景&#xff1a; ? 1&#xff09;斐波那契數列 ? 2&#xff09;遞歸 回溯 棧 先進后出 場景&#xff1a; ? 1&#xff09;path.resolve /a/b/…/c/d —> /a/c/d ? 2&#xff09;JSX ? 3&#xff09;加減乘…

VBA實現Excel的數據透視表

前言 本節會介紹通過VBA的PivotCaches.Create方法實現Excel創建新的數據透視表、修改原有的數據透視表的數據源以及刷新數據透視表內容。 本節測試內容以下表信息為例 1、創建數據透視表 語法&#xff1a;PivotCaches.Create(SourceType, [SourceData], [Version]) 說明&am…

打卡第8天-----字符串

進入字符串章節了,我真的特別希望把leetcode上的題快點全部都給刷完,我是社招準備跳槽才選擇這個訓練營的,面試總是掛算法題和編程題,希望通過這個訓練營我的算法和編程的水平能有所提升,抓住機會,成功上岸。我現在的這份工作,真的是一天都不想干了,但是下家工作單位還…

Spring——配置說明

1. 別名 別名&#xff1a;如果添加了別名&#xff0c;也可以使用別名獲取這個對象 <alias name"user" alias"user2"/> 2. Bean的配置 id&#xff1a;bean 的唯一標識符&#xff0c;也就是相當于我們學的對象名class&#xff1a;bean 對象所對應的…

無法解析主機:mirrorlist.centos.org Centos 7

從 2024 年 7 月 1 日起&#xff0c;在 CentOS 7 上&#xff0c;請切換到 Vault 存檔存儲庫&#xff1a; vi /etc/yum.repos.d/CentOS-Base.repo 復制/粘貼以下內容并注意您的操作系統版本。如果需要&#xff0c;請更改。此配置中的版本為 7.9.2009&#xff1a; [base] name…

Mac虛擬機跑Windows流暢嗎 Mac虛擬機連不上網絡怎么解決 mac虛擬機網速慢怎么解決

隨著技術的發展&#xff0c;很多用戶希望能在Mac電腦上運行Windows系統&#xff0c;從而能夠使用那些僅支持Windows系統的軟件。使用虛擬機軟件可以輕松滿足這一需求。但是&#xff0c;很多人可能會有疑問&#xff1a;“Mac虛擬機跑Windows流暢嗎&#xff1f;”&#xff0c;而且…

【AI前沿】深度學習基礎:訓練神經網絡

文章目錄 &#x1f4d1;前言一、前向傳播與反向傳播1.1 前向傳播&#xff08;Forward Propagation&#xff09;1.2 反向傳播&#xff08;Backpropagation&#xff09; 二、損失函數和優化算法2.1 損失函數&#xff08;Loss Function&#xff09;2.2 優化算法&#xff08;Optimi…

極狐Gitlab使用

目錄 續接上篇&#xff1a;極狐Gitlab安裝部署-CSDN博客 1. 關閉注冊功能 2. 創建群組 3. 創建用戶 5. 邀請成員到群組 6. 設置導入導出項目源 7. 通過gitee導入庫 8. 通過倉庫URL導入 9. 自創建項目 10. 默認分支main的權限 11. 使用普通用戶進入自建庫 12. 創建用…

python的isinstance和type

class A:passclass B(A)passbB()#isinstance可以進行繼承關系的判斷 print(isinstance(b,B))#Trueprint(isinstance(b,A))#Trueprint(type(b) is B)#Trueprint(type(b) is A)#Falseprint(type(b),A,B,b)#<class __main__.B> <class __main__.A> <class __main__…

B. Corner Twist(cf956)

題意&#xff1a;給你兩個網格&#xff0c;a和b&#xff0c;都是n行和 m 列。網格中的所有數值都是 0 &#xff0c; 1 或 2 。 您可以多次對 a&#x1d44e; 執行以下操作&#xff1a; 選取網格中任意一個長寬的子矩形。您可以選擇整個網格作為子矩形。子矩形有四個角。取所選…

【Linux 線程】線程的基本概念、LWP的理解

文章目錄 一、ps -L 指令&#x1f34e;二、線程控制 一、ps -L 指令&#x1f34e; &#x1f427; 使用 ps -L 命令查看輕量級進程信息&#xff1b;&#x1f427; pthread_self() 用于獲取用戶態線程的 tid&#xff0c;而并非輕量級進程ID&#xff1b;&#x1f427; getpid() 用…

生成日志系統和監控

背景&#xff1a;已知某后臺服務將日志存放在本地硬盤的日志文件中&#xff0c;該服務也支持代碼熱更新&#xff0c;并在完成熱更新后輸出一條日志。我們需要對服務日志進行監控&#xff0c;以確保文件熱更新后的錯誤能被第一時間發現。 我們提供 Python 程序模擬&#xff08;…

matlab仿真 模擬調制(上)

&#xff08;內容源自詳解MATLAB&#xff0f;SIMULINK 通信系統建模與仿真 劉學勇編著第五章內容&#xff0c;有興趣的讀者請閱讀原書&#xff09; 1.幅度調制 clear all ts0.0025; %信號抽樣時間間隔 t0:ts:10-ts;%時間矢量 fs1/ts;%抽樣頻率 dffs/length(t); %fft的頻率分…

國內從事人機交互的團隊——浙江工業大學

一、背景 當我們選擇一個新的課題后&#xff0c;需要清楚的了解從事該方向的團隊都有哪些&#xff0c;這樣可以及時跟蹤和學習大牛團隊的最新進展&#xff0c;以免自己認為的good idea&#xff0c;其實早就已經研究過了。 隨著人形機器人的發展&#xff0c;機器人不僅需要在無…

人類遠未觸及自然規律的本質

我想知道上帝是如何創造這個世界的&#xff0c;對于這樣或那樣的現象我不感興趣&#xff0c;我想知道的是他的思想&#xff0c;其余的都是細枝末節。——愛因斯坦 人類對自然規律的研究已經取得了不少進展&#xff0c;但是看起來研究清楚了原理&#xff0c;其實只是發現了更深…

【Windows】實現窗口子類化(基于遠程線程注入)

目錄 前言 原理解釋 完整項目 相關文獻 文章出處鏈接&#xff1a;[https://blog.csdn.net/qq_59075481/article/details/140334106] 前言 眾所周知&#xff0c;DLL 注入有多種用途&#xff0c;如熱修補、日志記錄、子類化等。本文重點介紹使用 DLL 注入對窗口進行子類化。…

mysql中count的區別

count(1)和count(*) 從執行計劃來看&#xff0c;count(1)和count(*)的效果是一樣的當表的數據量大些時&#xff0c;對表分析之后&#xff0c;使用count(1)還要比使用count(*)用時多當數據量在1W以內時&#xff0c;count(1)會比count(*)的用時少&#xff0c;不過也差不多如果cou…