C++ 在類里面使用多線程技術


前言

有很多時候,我們希望可以在C++類里面對那些比較耗時的函數使用多線程技術,但是熟悉C++對象語法的人應該知道,C++類的成員函數的函數指針不能直接做為參數傳到pthread_create,主要因為是C++成員函數指針帶有類命名空間,同時成員函數末尾是會被C++編譯器加上可以接收對象地址的this指針參數。因此需要將成員函數做一定的轉化,將其轉化為不被編譯器加上this指針,而由我們自己來為該函數維護”this”指針即可。

舉例分析

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <time.h> using namespace std; class Test { public: int sum=0; int cnt; public: int insert(); }; int Test::insert() { sleep(2); cnt+=1; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

如上所示,代碼聲明了一個類Test,假設該類有一個十分耗時的成員函數:insert(),這個求和函數每次執行需要2000ms的時間。對於如此耗時的函數,我們在設計時都會想方法將其設計為線程函數,這樣調用者才不會阻塞。 
於是我們為其加上多線程:

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <time.h> #include <unistd.h> #include <pthread.h> using namespace std; class Test { public: int sum=0; int cnt; public: int insert(); void * insert_pth(void*); void lanch(); }; int Test::insert() { sleep(2); sum+=1; } void * Test::insert_pth(void*) { insert(); } void Test::lanch() { pthread_t pth; pthread_create(&pth,NULL,insert_pth,NULL); } int main() { Test t; t.lanch(); return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

以上代碼通過調用lanch()來創建多線程來執行insert_pth,insert_pth 再調用insert(). 
但是 這樣的代碼在編譯時即會報錯。

pthread.cpp: In member function ‘void Test::lanch()’: pthread.cpp:30:42: error: invalid use of non-static member function pthread_create(&pth,NULL,insert_pth,NULL); 
  • 1
  • 2
  • 3
  • 4

只需將insert_pth變化為static函數,同時將insert邏輯代碼轉移到insert_pth即可

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <time.h> #include <unistd.h> #include <pthread.h> using namespace std; class Test { public: int sum=0; int cnt; public: int insert(); static void * insert_pth(void*); void lanch(); }; int Test::insert() { sleep(2); sum+=1; printf("%d insert.....\n",sum); } void * Test::insert_pth(void* __this) { Test * _this =(Test *)__this; sleep(2); _this->sum+=1; printf("%d insert.....\n",_this->sum); } void Test::lanch() { pthread_t pth; pthread_create(&pth,NULL,insert_pth,(void*)this); } int main() { Test t; t.sum=0; t.lanch(); sleep(5); return 0; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

總結

使用多線程處理耗時成員函數的步驟: 
1. 聲明另外一個靜態函數:static void XXX_pth(void __this); 
該函數與目標成員函數在函數名盡量保持一致 
2. 將原成員函數的代碼拷貝至void * XXX_pth(void * __this); 
在 XXX_pth()開始處將void * __this 轉化為 對象的指針 ObjectPoint _this; 
將拷貝下來的所有成員變量加上_this-> 
3. 編寫線程啟動代碼。 
注意pthread_create()最后一個參數傳入this指針

注意

在 XXX_pth()函數內容不要調用類的其它成員函數,否則成員函數將無法獲取正確的this指針而操作錯誤內存,從而導致segmantation fault.

在C++的類中,普通成員函數不能作為pthread_create的線程函數,如果要作為pthread_create中的線程函數,必須是static !

        在C語言中,我們使用pthread_create創建線程,線程函數是一個全局函數,所以在C++中,創建線程時,也應該使用一個全局函數。static定義的類的成員函數就是一個全局函數。

 

更多 參考  http://blog.csdn.net/ksn13/article/details/40538083 

 

 

復制代碼
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

class Thread
{
    private:
        pthread_t pid;
    private:
        static void * start_thread(void *arg);// //靜態成員函數
    public: 
        int start();
        virtual void run() = 0; //基類中的虛函數要么實現,要么是純虛函數(絕對不允許聲明不實現,也不純虛)
};

int Thread::start()
{
    if(pthread_create(&pid,NULL,start_thread,(void *)this) != 0) //´創建一個線程(必須是全局函數)
    {    
        return -1; 
    }    
    return 0;
}

void* Thread::start_thread(void *arg) //靜態成員函數只能訪問靜態變量或靜態函數,通過傳遞this指針進行調用
{
    Thread *ptr = (Thread *)arg;
    ptr->run();  //線程的實體是run
}



class MyThread:public Thread
{
    public: 
        void run();
};
void MyThread::run()
{
    printf("hello world\n");
}

int main(int argc,char *argv[])
{
    MyThread myThread;
    myThread.start();
    //test.run();
    sleep(1);
    return 0;
}
                          
復制代碼

編譯運行:

diego@ubuntu:~/myProg/pthreadCpp$ g++ main.cpp -lpthread
diego@ubuntu:~/myProg/pthreadCpp$ ./a.out 
hello world
diego@ubuntu:~/myProg/pthreadCpp$


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM