1. 程式人生 > >當執行緒函式為C++類成員函式時

當執行緒函式為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++獲取其成員函式方面的知識,請參考這個連結

http://www.zhihu.com/question/27738023

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指標)繫結之後便可高枕無憂的解決我們上述的所有問題了