C++11并發與多線程筆記(3)線程傳參詳解,detach()大坑,成員函數做線程函數

C++11并發與多線程筆記(3)線程傳參詳解,detach 大坑,成員函數做線程函數

  • 1、傳遞臨時對象作為線程參數
    • 1.1 要避免的陷阱1
    • 1.2 要避免的陷阱2
    • 1.3 總結
  • 2、臨時對象作為線程參數
    • 2.1 線程id概念
    • 2.2 臨時對象構造時機抓捕
  • 3、傳遞類對象、智能指針作為線程參數
    • 3.1 類對象作為線程參數
    • 3.2 智能指針作為線程參數
  • 4、用成員函數指針做線程函數

1、傳遞臨時對象作為線程參數

1.1 要避免的陷阱1

#include <iostream>
#include <thread>
using namespace std;void myPrint(const int &i, char* pmybuf)
{//如果線程從主線程detach了//i不是mvar真正的引用,實際上值傳遞,即使主線程運行完畢了,子線程用i仍然是安全的,但仍不推薦傳遞引用//推薦改為const int icout << i << endl;//pmybuf還是指向原來的字符串,所以這么寫是不安全的cout << pmybuf << endl;
}int main()
{int mvar = 1;int& mvary = mvar;char mybuf[] = "this is a test";thread myThread(myPrint, mvar, mybuf);//第一個參數是函數名,后兩個參數是函數的參數myThread.join();//myThread.detach();cout << "Hello World!" << endl;
}

在使用detach時,不推薦引用傳遞,指針傳遞肯定有問題

1.2 要避免的陷阱2

#include <iostream>
#include <thread>
#include <string>
using namespace std;void myPrint(const int i, const string& pmybuf)
{cout << i << endl;cout << pmybuf << endl;
}int main()
{int mvar = 1;int& mvary = mvar;char mybuf[] = "this is a test";//如果detach了,這樣仍然是不安全的//因為存在主線程運行完了,mybuf被回收了,系統采用mybuf隱式類型轉換成string//推薦先創建一個臨時對象thread myThread(myPrint, mvar, string(mybuf));就絕對安全了thread myThread01(myPrint, mvar, mybuf);//myThread01.join();myThread01.detach();cout << "I love China!" << endl;
}

在創建線程的同時構造臨時對象的方法傳遞參數是可行的

1.3 總結

  • 如果傳遞int這種基本數據類型,推薦使用值傳遞,不要用引用
  • 如果傳遞類對象,避免使用隱式類型轉換,全部都是創建線程這一行就創建出臨時對象,然后在函數參數里,用引用來接,否則還會創建出一個對象
  • 終極結論:建議不使用detach,只使用join,這樣就不存在局部變量失效導致線程對內存的非法引用問題。

2、臨時對象作為線程參數

2.1 線程id概念

  • id是個數字,每個線程(不管是主線程還是子線程)實際上都對應著一個數字,而且每個線程對應的這個數字都不一樣。
  • 線程id可以用C++標準庫里的函數來獲取。**std::this_thread::get_id()**來獲取

2.2 臨時對象構造時機抓捕

#include<iostream>
#include<thread>
using namespace std;
class A {
public:int m_a;A(int a) :m_a(a) {cout << "A(int a):m_a(a)構造函數執行" << this << "  線程id為:" <<this_thread::get_id << endl;}A(const A& a):m_a(a.m_a){cout << "A(const A& a):m_a(a.m_a)拷貝構造函數執行" << this <<"  線程id為:" << this_thread::get_id << endl;}~A() {cout << "~A() 析構函數執行" << this <<"  線程id為:" << this_thread::get_id << endl;}};
void myPrint(const int i, const A& pmybuf) {cout << i << endl;cout << pmybuf.m_a<< endl;
}
int main() {int mvar = 1;int myseconder = 12;cout<<"主線程id為:"<< this_thread::get_id() << endl;thread myThread01(myPrint, mvar, A(myseconder));myThread01.detach();cout << "hello world" << endl;
}

在這里插入圖片描述

3、傳遞類對象、智能指針作為線程參數

3.1 類對象作為線程參數

#include <iostream>
#include <thread>
using namespace std;class A {
public:mutable int m_i; //m_i即使實在const中也可以被修改A(int i) :m_i(i) {}
};void myPrint(const A& pmybuf)//雖然是參數引用,但還是沒有修改主線程中m_i值
{pmybuf.m_i = 199;//修改的值不影響main函數cout << "子線程myPrint的參數地址是" << &pmybuf << "thread = " << std::this_thread::get_id() << endl;
}int main()
{A myObj(10);//myPrint(const A& pmybuf)中引用不能去掉,如果去掉會多創建一個對象//const也不能去掉,去掉會出錯//即使是傳遞的const引用,但在子線程中還是會調用拷貝構造函數構造一個新的對象,//所以在子線程中修改m_i的值不會影響到主線程//如果希望子線程中修改m_i的值影響到主線程,可以用thread myThread(myPrint, std::ref(myObj));,省去了傳遞時的拷貝構造函數//這樣const就是真的引用了,myPrint定義中的const就可以去掉了,類A定義中的mutable也可以去掉了thread myThread(myPrint, myObj);myThread.join();//myThread.detach();cout << "Hello World!" << endl;
}

分析:

  • void myPrint(const A& pmybuf)//雖然是參數引用(& pmybuf),但還是沒有修改主線程中m_i值
  • 如果希望子線程中修改m_i的值影響到主線程,可以用thread myThread(myPrint, std::ref(myObj));

3.2 智能指針作為線程參數

#include <iostream>
#include <thread>
#include <memory>
using namespace std;void myPrint(unique_ptr<int> ptn)
{cout << "thread = " << std::this_thread::get_id() << endl;
}int main()
{unique_ptr<int> myp(new int(10));//獨占式智能指針只能通過std::move()才可以傳遞給另一個指針//傳遞后up就指向空,新的ptn指向原來的內存//所以這時就不能用detach了,因為如果主線程先執行完,ptn指向的對象就被釋放了thread myThread(myPrint, std::move(myp));myThread.join();//myThread.detach();return 0;
}

分析:

  • unique_ptr 構造函數已經將拷貝函數和拷貝賦值刪除了,禁止拷貝,如果需要將unique_ptr對象傳入,需要使用std::move(myp)

4、用成員函數指針做線程函數

class A {
public:int m_a;A(int a) :m_a(a) {cout << "A(int a):m_a(a)構造函數執行" << this << "  線程id為:" <<this_thread::get_id << endl;}A(const A& a):m_a(a.m_a){cout << "A(const A& a):m_a(a.m_a)拷貝構造函數執行" << this <<"  線程id為:" << this_thread::get_id << endl;}~A() {cout << "~A() 析構函數執行" << this <<"  線程id為:" << this_thread::get_id << endl;}void thread_work(int i) {cout << "子線程thread_work執行" << this <<"  thread_work線程id為:" << this_thread::get_id << endl;}void operator()(int i){cout << "子線程operator()執行" << this <<"  operator()線程id為:" << this_thread::get_id << endl;}
};int main() {cout<<"主線程id為:"<< this_thread::get_id() << endl;A myobj(10);//生成一個類對象;//參數1:傳成員函數地址//參數2:對象名//參數3:函數所需的參數thread myThread(&A::thread_work,myobj,15)// &myobj==std::ref(myobj) 不調用拷貝構造函數了,那后續如果調用myThread就不安全了//thread myThread(myobj,15) //使用 operator()作為子線程入口myThread.detach();cout << "hello world" << endl;
}

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

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

相關文章

VR時代真的到來了?

業界對蘋果的期待是&#xff0c;打造一臺真正顛覆性的&#xff0c;給頭顯設備奠定發展邏輯底座的產品&#xff0c;而實際上&#xff0c;蘋果只是發布了一臺更強大的頭顯。 大眾希望蘋果回答的問題是“我為什么需要一臺AR或者VR產品&#xff1f;”&#xff0c;但蘋果回答的是“…

從零開始學習 Java:簡單易懂的入門指南之MAth、System(十二)

常見API&#xff0c;MAth、System 1 Math類1.1 概述1.2 常見方法1.3 算法小題(質數)1.4 算法小題(自冪數) 2 System類2.1 概述2.2 常見方法 1 Math類 1.1 概述 tips&#xff1a;了解內容 查看API文檔&#xff0c;我們可以看到API文檔中關于Math類的定義如下&#xff1a; Math類…

每天一道leetcode:300. 最長遞增子序列(動態規劃中等)

今日份題目&#xff1a; 給你一個整數數組 nums &#xff0c;找到其中最長嚴格遞增子序列的長度。 子序列 是由數組派生而來的序列&#xff0c;刪除&#xff08;或不刪除&#xff09;數組中的元素而不改變其余元素的順序。例如&#xff0c;[3,6,2,7] 是數組 [0,3,1,6,2,2,7] …

【JavaEE進階】SpringBoot項目的創建

文章目錄 一. SpringBoot簡介1. 什么是SpringBoot?2. SpringBoot的優點 二. SpringBoot項目創建1. 使用IDEA創建2. 使用網頁創建SpringBoot項目 三. 運行SpringBoot項目 一. SpringBoot簡介 1. 什么是SpringBoot? Spring Boot 是一個用于快速構建基于 Spring 框架的應用程序…

Spring對象裝配

在spring中&#xff0c;Bean的執行流程為啟動spring容器&#xff0c;實例化bean&#xff0c;將bean注冊到spring容器中&#xff0c;將bean裝配到需要的類中。 既然我們需要將bea裝配到需要的類中&#xff0c;那么如何實現呢&#xff1f;這篇文章&#xff0c;將來闡述一下如何實…

SOFABoot——基本使用(筆記)

文章目錄 一、前言二、快速開始2.1 基本搭建2.2 測試是否成功2.3 其他部分日志測試異步啟動 三、SOFABoot的模塊化開發3.1 基于Spring上下文的隔離3.2 Root Application Context3.3 模塊并行化啟動3.4 JVM服務與RPC服務的發布與引用3.5 模塊配置Module-NameRequire-ModuleSprin…

wsl2安裝mysql環境

安裝完mysql后通過如下命令啟動mysql service mysql start 會顯示如下錯誤&#xff1a; mysql: unrecognized service 實際上上面顯示的錯誤是由于mysql沒有啟動成功造成的 我們要想辦法成功啟動mysql才可以 1.通過如下操作就可以跳過密碼直接進入mysql環境 2.如果想找到my…

微服務與Nacos概述-5

引入OpenFeign 添加依賴&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency><groupId>com.alibaba.cloud</groupId>…

“記賬”很麻煩,看這場競賽中的隊伍與合合信息是如何解決問題的

在我們日常生活中或多或少都會有記賬的情況&#xff0c;以此來對自己的收支和消費習慣進行分析&#xff0c;來幫助自己減少不必要的開支&#xff0c;優化財務決策、合理分配資金&#xff0c;減少財務壓力和不必要的浪費。 但記賬這個動作本身就是一件比較麻煩的。雖然現階段有…

數據結構入門 — 時間復雜度、空間復雜度

前言 數據結構_空間復雜度_時間復雜度講解_常見復雜度對比 本文介紹數據結構中的時間復雜度和空間復雜度 ***文章末尾&#xff0c;博主進行了概要總結&#xff0c;可以直接看總結部分*** 博主博客鏈接&#xff1a;https://blog.csdn.net/m0_74014525 點點關注&#xff0c;后期…

哈夫曼樹(赫夫曼樹、最優樹)詳解

目錄 哈夫曼樹&#xff08;赫夫曼樹、最優樹&#xff09;詳解 哈夫曼樹相關的幾個名詞 什么是哈夫曼樹 構建哈夫曼樹的過程 哈弗曼樹中結點結構 構建哈弗曼樹的算法實現 哈夫曼樹&#xff08;赫夫曼樹、最優樹&#xff09;詳解 哈夫曼樹相關的幾個名詞 路徑&#xff1a;…

2023牛客暑期多校訓練營8(A/H/I/J)

目錄 A.Alive Fossils H.Insert 1, Insert 2, Insert 3, ... I.Make It Square J.Permutation and Primes A.Alive Fossils 思路&#xff1a;一開始題意看半天沒看懂&#xff0c;后面發現只需要輸出t組輸入中&#xff0c;都出現過的字符串即可。 代碼&#xff1a; void s…

實驗三 圖像分割與描述

一、實驗目的&#xff1a; &#xff08;1&#xff09;進一步掌握圖像處理工具Matlab&#xff0c;熟悉基于Matlab的圖像處理函數。 &#xff08;2&#xff09;掌握圖像分割方法&#xff0c;熟悉常用圖像描述方法。 二、實驗原理 1.膚色檢測 膚色是人類皮膚重要特征之一&#xff…

7.原 型

7.1原型 【例如】 另外- this指向&#xff1a; 構造函數和原型對象中的this都指向實例化的對象 7.2 constructor屬性 每個原型對象里面都有個constructor屬性( constructor構造函數) 作用&#xff1a;該屬性指向該原型對象的構造函數 使用場景: 如果有多個對象的方法&#…

Springboot 實踐(4)swagger-ui 測試controller

前文項目操作&#xff0c;完成了項目的創建、數據源的配置以及數據庫DAO程序的生成與配置。此文講解利用swagger-ui界面&#xff0c;測試生成的數據庫DAO程序。目前&#xff0c;項目swagger-ui界面如下&#xff1a; 以”用戶管理”為例&#xff0c;簡單講述swagger-ui測試數據庫…

無涯教程-Perl - s函數

描述 這不是功能。這是正則表達式替換運算符。根據PATTERN中指定的正則表達式,將數據替換為REPLACE。與m //一樣,分隔符由s后的第一個字符定義。 語法 以下是此函數的簡單語法- s/PATTERN/REPLACE/返回值 如果失敗,此函數返回0,如果成功,則返回替換次數。 例 以下是顯示…

筆記:移植xenomai到nuc972

xenomai是一個實時操作系統,想要使用它,先要移植I-pipe補丁 補丁在xenomai / ipipe-arm GitLab 我的內核是4.4-248的,合并上去會有幾個小錯誤,隨便改改就好 編譯內核沒有報錯之后,接下來需要修改arch/arm/mach-nuc970/time.c 修改方法參考補丁里面其它設備的定時器驅動,就…

學習Vue:數據綁定的基本概念

在 Vue.js 中&#xff0c;Vue 實例是您構建應用程序的核心。它允許您將數據和界面連接起來&#xff0c;實現動態的數據綁定&#xff0c;使您的應用程序能夠根據數據的變化自動更新界面。讓我們來深入了解 Vue 實例與數據綁定的基本概念。 Vue 實例與數據綁定 什么是 Vue 實例&…

OPC【2】——Relationships

引言 Relationships由一系列Relationship構成。將Abstract Package看做是一個圖數據結構&#xff0c;則Relationships是圖數據中的邊集合。 Package Relationships 對于Package Relationships&#xff0c;其所有引用關系的source對象為Abstract Package&#xff0c;或者看…

【Python機器學習】實驗10 支持向量機

文章目錄 支持向量機實例1 線性可分的支持向量機1.1 數據讀取1.2 準備訓練數據1.3 實例化線性支持向量機1.4 可視化分析 實例2 核支持向量機2.1 讀取數據集2.2 定義高斯核函數2.3 創建非線性的支持向量機2.4 可視化樣本類別 實例3 如何選擇最優的C和gamma3.1 讀取數據3.2 利用數…