2015-09-12 43 views
0

我有這樣一個要求: - 1)有兩個類,比如Wrapper和Wrapper2。 2)Wrapper2包含Wrapper類的引用對象。 3)線程將數據寫入Wrapper類的一個變量,該變量本質上應該是調用Wrapper的成員函數。 4)另一個線程可以讀寫數據給Wrapper的類成員,這個線程本質上是通過Wrapper2調用的。Pthread對於使用類對象引用的C++類函數

基於一些關於Stackoverflow的老問題的答案,我創建了一個示例代碼來檢查爲什麼我的生產代碼失敗,我無法找出問題所在。只要thread2被創建,它就會收到SIGSEG信號。代碼如下: -

#include <thread> 
    #include <iostream> 
    #include <chrono> 
    #include <unistd.h> 
    #include <stdlib.h> 
    #include <signal.h> 
    #include <stdio.h> 
    #include <signal.h> 
    #include <pthread.h> 
    #include <wait.h> 
    #include <string.h> 

    pthread_mutex_t mt1; 

    void thread_signal(int signum) 
    { 
     pthread_exit(0); 
    } 

    void sig_func(int sig) 
    { 
    write(1, "Caught signal 11\n", 17); 
    std::cout<<"Caught signal :"<<sig<<std::endl; 
    signal(SIGSEGV,sig_func); 
    thread_signal(sig); 
    } 

    class Wrapper { 
     public: 
     Wrapper():i(10) 
     { 
      std::cout<<"Wrapper Constructor Called. "<<this<<" \n"; 
     } 
     ~Wrapper() 
     { 
      std::cout<<"Wrapper Destructor Called. "<<this<<"\n"; 
     } 
      void member1() { 
       std::cout << "i am member1" << std::endl; 
      } 
      void member2(const char *arg1, unsigned arg2) { 
       std::cout << "i am member2 and my first arg is (" << arg1 << ") and second arg is (" << arg2 << ")" << std::endl; 
      } 
     void setI(int i) 
     { 
      pthread_mutex_lock(&mt1); 
      this->i=i; 
      std::cout<<"set: "<< this->i<<std::endl; 
      pthread_mutex_unlock(&mt1); 
     } 
     int getI() 
     { 
      pthread_mutex_lock(&mt1); 
      std::cout<<"get: "<< this->i<<std::endl; 
      pthread_mutex_unlock(&mt1); 
      return 0; 
     } 
     int i; 
    }; 

    class Wrapper2 
    { 
    public: 
     Wrapper2(Wrapper & wp):wp2(wp) 
    { 
      std::cout<<"Wrapper2 Constructor Called. "<<this<<" \n"; 
    } 

     ~Wrapper2() 
     { 
      std::cout<<"Wrapper2 Destructor Called. "<<this<<" \n"; 
     } 
     Wrapper & wp2; 
    }; 


    struct ThreadWrapper { 
     Wrapper & wr1; 
     Wrapper2 & wr2; 

     ThreadWrapper(Wrapper & wr1,Wrapper2& wr2): 
        wr1(wr1),wr2(wr2) 
     { 

     } 

    }; 

    extern "C" void* wrapper1Fun (void* wr1) 
    { 
     std::auto_ptr<Wrapper> wrp1 (static_cast< Wrapper* >(wr1)); 
     std::cout<<"Thread 1 created. \n"; 
     while(1) 
     { 
      wrp1->setI(rand()%100); 
      usleep(50); 
     } 

     return 0; 
    } 

    extern "C" void* wrapper2Fun (void* wr2) 
    { 
     std::auto_ptr<Wrapper2> wrp2 (static_cast< Wrapper2* >(wr2)); 
     std::cout<<"Thread 2 created. \n"; 
     while(1) 
     { 
      wrp2->wp2.getI(); 
      usleep(50); 
     } 

     return 0; 
    } 

    int main(int argc, char **argv) { 
     struct sigaction sa; 
     memset(&sa, 0, sizeof(sa)); 
     sa.sa_handler = thread_signal; 
     sa.sa_flags = 0; 
     sigaction(SIGTERM, &sa, 0); 
     bool mainRunning= true; 
     Wrapper w; 
     Wrapper2 w1(w); 

     sleep(1); 
     ThreadWrapper * myWrap = new ThreadWrapper(w,w1); 
     sleep(1); 
     pthread_t pt1; 
     pthread_t pt2; 
     pthread_attr_t attr; 
     signal(SIGSEGV,sig_func); // Register signal handler before going multithread 
     pthread_attr_init(&attr); 
     int i = pthread_create(&pt1, NULL,wrapper1Fun, myWrap); 
     std::cout<<"First thread status "<<i<<std::endl; 
     sleep(1); 
     int j = pthread_create(&pt2, &attr,wrapper2Fun, myWrap); 
     std::cout<<"Second thread status "<<j<<std::endl; 
     sleep(1); 
     while(1); 
     fprintf(stderr, "kill thread\n"); 
     //pthread_kill(pt1, SIGTERM); 
     fprintf(stderr, "join thread\n"); 
     pthread_join(pt1, NULL); 
     pthread_join(pt1, NULL); 

     return 0; 
    } 
+1

是什麼讓你覺得你需要使用'std :: auto_ptr'? –

+0

包裝周圍的包裝。非常複雜。 –

回答

3

wrapper1Fun希望傳遞一個指向Wrapper,並wrapper2Fun希望傳遞一個指針Wraper2。但是你實際上將一個指向ThreadWrapper的指針傳遞給每一個,這是一個完全不同的類型,所以它出錯了。

使用void *和強制轉換可以防止編譯器指出您的類型錯誤。我建議使用類型安全的C++線程庫而不是原始的pthread。 Boost有一個,就像C++ 11的標準庫一樣。

另外,您最好使用auto_ptr。它被棄用,很容易出錯,表達所有權的不良方式 - 更喜歡unique_ptrshared_ptr

這裏您構造了兩個擁有相同指針的auto_ptr值,所以它將被釋放兩次,這是未定義的行爲。

在任何情況下,沒有明顯的理由將這些對象放在堆上。如果你這樣做,你需要決定內存的所有權在哪裏。

+0

謝謝@Alan,你節省了我的一天和幾個小時的挫折。我只是無法弄清楚。我想使用C++ 11線程,我也做了,那麼這裏的人只想要pthread,然後我需要再次編寫整個代碼。代碼失敗了,因此我編寫了一個示例代碼來測試我的東西。關於auto_ptr,我認爲一個普通的指針會更好。我在這裏錯了嗎?你能詳細說一下嗎?提前致謝。 –

+0

請參閱已編輯的答案。 –

+0

你好@Alan,再次感謝你的回答。我明白了這個問題。 –