c++ 學習之 多線程(二) thread的參數傳遞
前言
上一篇文章中講了thread的四種構造函數,接下來給大家講一講thread的參數傳遞。
正文
1.初始化構造函數
利用初始化構造函數創建對象,第一個位置必須要傳入一個可調用對象。c++ 中的可調用對象大概有這麼幾種:普通函數 ,類成員函數,類靜態函數,仿函數,函數指針,lambda表達式,std::function。不瞭解可調用對象的可以戳這裏,我寫的另一篇關於可調用對象的文章。
(1)普通函數
用普通函數來初始化thread對象很簡單,只需要把函數名傳進去即可,函數中的參數按照順序傳入:
#include<stdio.h>
#include<thread>
void fun(int a,int b)
{
printf("%d\n",a+b);
}
int main()
{
int a =1;
int b =2;
std::thread t(fun,a,b);
t.join();
}
輸出結果爲 : 3
(2)類成員函數
類成員函數是有真正地址的,利用 &類名::函數名 可以拿到成員函數的地址。注意,最好先創建一個了類對象,不建議用臨時對象。第二位參數傳入該對象。
#include<stdio.h>
#include<thread>
class A
{
public:
void fun(int a,int b)
{
printf("%d\n",a+b);
}
};
int main()
{
int a =1;
int b =2;
A c;
std::thread t(&A::fun,c,a,b);
t.join();
}
輸出結果爲 : 3
(3)類靜態成員函數
類靜態成員函數不需要指定類對象。
#include<stdio.h>
#include<thread>
class A
{
public:
static void fun(int a,int b)
{
printf("%d\n",a+b);
}
};
int main()
{
int a =1;
int b =2;
std::thread t(&A::fun,a,b);
t.join();
}
輸出結果爲: 3
(4) 仿函數(即用類對象創建線程)
仿函數是使用類來模擬函數調用行爲,我們只要重載一個類的operator()方法,即可像調用一個函數一樣調用類。這種方式用得比較少。
#include<stdio.h>
#include<thread>
class A
{
public:
void operator()(int a,int b)//實現了對()的重載
{
printf("%d\n",a+b);
}
};
int main()
{
int a =1;
int b =2;
A c;
std::thread t(c,a,b);
t.join();
}
輸出結果爲 : 3
我們只需要在類的內部對() 進行重載,然後就可以將該類的對象作爲可調用對象初始化thread。
(5)函數指針
沒啥說的,函數指針的使用,和回調函數用法差不多。
#include<stdio.h>
#include<thread>
void fun(int a, int b)
{
printf("%d\n", a + b);
}
int main()
{
int a = 1;
int b = 2;
void (*p)(int, int) = fun;
std::thread t(p, a, b);
t.join();
}
輸出結果爲 : 3
(6)lambda表達式
將匿名函數作爲可調用對象創建thread。
#include<stdio.h>
#include<thread>
int main()
{
int a = 1;
int b = 2;
auto c = [](int a, int b) {printf("%d\n", a + b); };
std::thread t(c, a, b);
t.join();
}
輸出結果爲 : 3
(7) std::function
std::function 可以用來描述C++中的可調用實體,它可以兼容所有可調用對象,自然也可以通過它來初始化thread對象。
#include<stdio.h>
#include<thread>
#include<functional>
std::function<void(int, int)> Function;
//普通函數
void fun(int a,int b)
{
printf("普通函數:%d\n", a + b);
}
void fun2(int a, int b)
{
printf("函數指針:%d\n", a + b);
}
class A
{
public:
//類成員函數
void fun1(int a, int b)
{
printf("類成員函數:%d\n", a + b);
}
//靜態成員函數
static void fun2(int a, int b)
{
printf("靜態成員函數:%d\n", a + b);
}
//仿函數
void operator ()(int a, int b)
{
printf("仿函數(類對象):%d\n", a + b);
}
};
int main()
{
int a = 1;
int b = 2;
//lambda表達式
auto lam = [](int a, int b) {printf("lambda表達式:%d\n", a + b); };
Function = lam;
std::thread t1(Function, a, b);
t1.join();
//函數指針
void(*p)(int, int) = fun2;
Function = p;
t1 = std::thread(Function, a, b);
t1.join();
//靜態成員函數
Function = &A::fun2;
t1 = std::thread(Function, a, b);
t1.join();
//成員函數
A c;
Function = std::bind(&A::fun1,c, std::placeholders::_1, std::placeholders::_2);// 此時將對象c指定爲對象實例
t1 = std::thread(Function,a,b);// 這裏不用將c傳進去了
t1.join();
//仿函數
A d;
Function = d;
t1 = std::thread(Function, a, b);
t1.join();
}
輸出結果:
lambda表達式:3
函數指針:3
靜態成員函數:3
類成員函數:3
仿函數(類對象):3
可以用到的初始化的方式大概就這樣幾種,都得用到可調用對象。
2.移動構造函數
首先我們要明白移動構造函數的用途,是把一個thread對象的線程轉移到構造出來的thread對象上,可以通俗的理解成一次性賦值,過後被移動的thread對象將不在執行線程。但是我們不也能直接將被移動thread對象作爲參數傳進去,需要用std::move(),將它轉換爲右值。
#include<stdio.h>
#include<thread>
void fun()
{
printf("I love China\n");
}
int main()
{
std::thread t(fun);
std::thread t1(std::move(t));
t1.join();
}