當執行緒函式為C++類成員函式時
很多時候我們在C++多執行緒開發時,都會或多或少遇到執行緒函式為C++類中的某個成員函式,此時可能會發生什麼呢?你有可能會雜麼做呢?
接下來我就為大家總結一下我在這方面走過的一個歷程
1.問題一
記得我在之前在寫一個udp傳輸檔案的程式時,我就第一次遇到了執行緒函式為C++類的成員函式,當時遇到的問題,大概意思如下:
#include<iostream>
#include <thread>
#include <unistd.h>
class Test
{
public:
Test():testThread_(print)
{
}
void print(void)
{
std::cout<<"hello"<<std::endl;
}
private:
std::thread testThread_;
};
int main(int argc,char **argv)
{
Test test;
sleep(1000);
return 0;
}
如上述程式碼,當我編譯時會產生如下編譯結果
根據第一個error報錯,貌似程式希望我們把print函式設為靜態函式,第二個error則意思是我們傳遞的引數不能和std::thread所匹配。我的前幾篇博文有寫過std::thread相關的知識,它的第一個引數為函式指標,而我們的標準C++裡這樣是獲取不到其成員函式的指標的所以才會產生上述的報錯。關於C++獲取其成員函式方面的知識,請參考這個連結
2.(一)解決方案
根據一種的報錯,我想我們想到的最簡單的方法就是把成員函式設成靜態成員函式
具體如下
#include<iostream>
#include <thread>
#include <unistd.h>
class Test
{
public:
Test():testThread_(print)
{
}
static void print(void)
{
std ::cout<<"hello"<<std::endl;
}
private:
std::thread testThread_;
};
int main(int argc,char **argv)
{
Test test;
sleep(1000);
return 0;
}
這個程式碼解決了我在一中遇到的問題
3.問題二
2中似乎表面上解決了我的問題,但事實上由於2的解決方案,我又遇到了新的問題
#include<iostream>
#include <thread>
#include <unistd.h>
class Test
{
public:
Test(int m):n(m),testThread_(print)
{
}
static void print(void)
{
std::cout<<n<<std::endl;
}
private:
int n;
std::thread testThread_;
};
int main(int argc,char **argv)
{
Test test(8);
sleep(1000);
return 0;
}
在上述程式碼中,當我的執行緒函式在使用類的成員函式時,編譯時會報錯
這是因為,我們的靜態成員函式並不能使用非靜態的成員變數(因為它沒有某個具體物件的this指標)
4.(二)解決方案1
解決方案很簡單,我們只需給靜態成員函式傳遞某物件的this指標即可
具體如下
#include<iostream>
#include <thread>
#include <unistd.h>
class Test
{
public:
Test(int m):n(m),testThread_(print,this)
{
}
static void print(Test *pt)
{
std::cout<<pt->n<<std::endl;
}
private:
int n;
std::thread testThread_;
};
int main(int argc,char **argv)
{
Test test(8);
sleep(1000);
return 0;
}
5.(二)解決方案2
4中的確完全解決了我們線上程中呼叫類的成員函式的所有問題,但是你會不會感覺其用起來很彆扭,本來我們只是向使一個成員函式為執行緒函式,這樣我們就可以在該執行緒函式中直接使用該類的成員變量了,但是由於2中有敘述的那些原因,結果使我們不得不使用將成員函式設為靜態的,結果就是我們現在使用類的成員變數會這麼麻煩,感覺好不爽。難道就沒什麼方法可以讓我們不是成員函式變為靜態的?
哈哈,當然是有的具體方案如下
#include<iostream>
#include <thread>
#include <unistd.h>
#include <functional>
class Test
{
public:
Test(int m):n(m),testThread_(std::bind(&Test::print,this))
{
}
void print(void)
{
std::cout<<n<<std::endl;
}
private:
int n;
std::thread testThread_;
};
int main(int argc,char **argv)
{
Test test(8);
sleep(1000);
return 0;
}
我們可以像上述程式碼那樣只需用C++11新標準的std::bind函式將其成員函式與對應的物件指標(即this指標)繫結之後便可高枕無憂的解決我們上述的所有問題了