2014-01-05 19 views
0

現在已修復。我已經增加了一個程序來顯示它是如何修復的。該程序旨在演示在多線程環境中信號如何丟失。這種信號損失會導致競爭狀態。阻塞線程永遠不會獲取解鎖信號,因爲它會錯過信號。這有條件,和互斥。解決這類問題的方法是使用cond_var。 cond_var保護條件以及數據。因此,它會自動鎖定條件,一旦其他線程發出信號就會解除條件。條件鎖定可以防止信號遺漏。錯誤的程序 - 比賽條件程序被添加到這裏。如何在Linux中傳遞信號以解除暫停()?

我有以下程序。我試圖通過電話解鎖它 - 殺人。但是,我的程序掛起,因爲它永遠不會發送信號給阻塞的函數()。我不想使用pthread_cond,因爲我想在這裏演示這個問題。但是信號不會丟失,但它永遠不會通過信號來解鎖它。

#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <iostream> 
/** get pid **/ 
#include <sys/types.h> 
#include <unistd.h> 
/** kill signal **/ 
#include <signal.h> 

using namespace std; 

int shared_variable = 7; 

pid_t pid_A; 
pid_t pid_B; 



class helium_thread 
{ 
    private: 
    pthread_t *thread_id; 
    pid_t process_pid; 

    public: 
    static pthread_mutex_t mutex_thread; 
    void set_thread_id(pthread_t tid); 
    pthread_t *get_thread_id(); 
    int create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg); 
    helium_thread(); 
    ~helium_thread(); 

}; 

helium_thread thread_1, thread_2; 

void helium_thread::set_thread_id(pthread_t tid) 
{ 
    *(this->thread_id) = tid;  
} 

pthread_t * helium_thread::get_thread_id() 
{ 
    return (this->thread_id); 
} 

int helium_thread::create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg) 
{ 
    int ret; 
    ret = pthread_create(thread_ptr,attr,start_routine,(void *)arg) ; 
    cout<<"Thread created "<<std::hex<<thread_ptr<<endl; 
    return ret; 

} 

helium_thread::helium_thread() 
{ 

    thread_id = new pthread_t; 
    cout<<"Constructor called "<<std::hex<<thread_id<<endl; 
} 

helium_thread::~helium_thread() 
{ 
    cout<<"Destructor called"<<std::hex<<thread_id<<endl; 
    delete thread_id; 
} 

/** While defining the methods of the class, Keywords static and virtual should not be repeated in the definition. **/ 
/** They should only be used in the class declaration. **/ 

void *Thread_Function_A(void *thread_arg) 
{ 
    int rc = 0; 
    pthread_mutex_lock(&(helium_thread::mutex_thread)); 

    pid_A = getpid(); 

    cout<<"The pid value of Thread A is"<< pid_A << endl; 

    if (shared_variable == 5) 
    { 
     shared_variable = 100; 
     cout<<"The thread A proceeds"<<endl; 
     pthread_mutex_unlock(&(helium_thread::mutex_thread)); 

    } 
    else 
    { pthread_mutex_unlock(&(helium_thread::mutex_thread)); 
     cout<<"Going to block now"<<endl; 
     rc = pause(); 
     cout<<"Unblocked now, the rc value is "<<rc<<endl; 

    } 



} 

void *Thread_Function_B(void *thread_arg) 
{ 
    pthread_mutex_lock(&(helium_thread::mutex_thread)); 

    pid_B = getpid(); 

    cout<<"The pid value of Thread B is"<< pid_B << endl; 

    shared_variable = 5; 

    cout<<"Unblock the thread A now"<<endl; 
    pthread_kill(*(thread_1.get_thread_id()), SIGCONT); 


    pthread_mutex_unlock(&(helium_thread::mutex_thread)); 

} 

/** The definition of the static member can't be inside a function, You need to put it outside **/ 
/** When I tried using inside a function, I got the error - error: invalid use of qualified-name ‘helium_thread::mutex_thread **/ 

pthread_mutex_t helium_thread::mutex_thread = PTHREAD_MUTEX_INITIALIZER; 

int main(int argc, char *argv[]) 
{ 

    pid_t thread_pid_val = getpid(); 

    thread_1.create_thread((thread_1.get_thread_id()),NULL,Thread_Function_A,&thread_pid_val); 
    thread_2.create_thread((thread_2.get_thread_id()),NULL,Thread_Function_B,&thread_pid_val); 
    pthread_join(*(thread_1.get_thread_id()), NULL); 
    pthread_join(*(thread_2.get_thread_id()), NULL); 

    return 0; 
} 

輸出是 -

$ ./thread_basic.out 
Constructor called 0x195c010 
Constructor called 0x195c030 
Thread created 0x195c010 
The pid value of Thread A is404c 
Thread created Going to block now 
The pid value of Thread B is0x404c 
Unblock the thread A now 
0x195c030 

------------------工作種族 - 條件

計劃專
#include <stdio.h> 
#include <stdlib.h> 
#include <pthread.h> 
#include <iostream> 
/** get pid **/ 
#include <sys/types.h> 
#include <unistd.h> 
/** kill signal **/ 
#include <signal.h> 

using namespace std; 

int shared_variable = 7; 

pid_t pid_A; 
pid_t pid_B; 



class helium_thread 
{ 
    private: 
    pthread_t *thread_id; 
    pid_t process_pid; 

    public: 
    static pthread_mutex_t mutex_thread; 
    void set_thread_id(pthread_t tid); 
    pthread_t *get_thread_id(); 
    int create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg); 
    helium_thread(); 
    ~helium_thread(); 

}; 

helium_thread thread_1, thread_2; 

void helium_thread::set_thread_id(pthread_t tid) 
{ 
    *(this->thread_id) = tid;  
} 

pthread_t * helium_thread::get_thread_id() 
{ 
    return (this->thread_id); 
} 

int helium_thread::create_thread(pthread_t *thread_ptr, const pthread_attr_t *attr, void * (*start_routine)(void *), void *arg) 
{ 
    int ret; 
    ret = pthread_create(thread_ptr,attr,start_routine,(void *)arg) ; 
    cout<<"Thread created "<<std::hex<<thread_ptr<<endl; 
    return ret; 

} 

helium_thread::helium_thread() 
{ 

    thread_id = new pthread_t; 
    cout<<"Constructor called "<<std::hex<<thread_id<<endl; 
} 

helium_thread::~helium_thread() 
{ 
    cout<<"Destructor called"<<std::hex<<thread_id<<endl; 
    delete thread_id; 
} 

/** While defining the methods of the class, Keywords static and virtual should not be repeated in the definition. **/ 
/** They should only be used in the class declaration. **/ 

void handler(int sig) 
{ 
    //do nothing 
    cout<<"Handler called"<<endl; 
} 


void *Thread_Function_A(void *thread_arg) 
{ 
    int rc = 0; 
    pthread_mutex_lock(&(helium_thread::mutex_thread)); 

    pid_A = getpid(); 

    cout<<"The pid value of Thread A is"<< pid_A << endl; 

    while(1) 
    { 

    if (shared_variable == 5) 
    { 
     shared_variable = 100; 
     cout<<"The thread A proceeds"<<endl; 
     cout<<"The shared_variable value = "<< std::dec<< shared_variable << endl; 
     pthread_mutex_unlock(&(helium_thread::mutex_thread)); 
     cout<<"The thread exits"<<endl; 
     pthread_exit(NULL); 

    } 
    else 
    { pthread_mutex_unlock(&(helium_thread::mutex_thread)); 
     cout<<"Going to block now"<<endl; 
     /** This sleep will give a sufficient time to schedule thread B **/ 
     /** Once thread B is scheduled, the thread B will sent a signal to unblock the thread A **/ 
     /** The signal has been sent, but this thread was not in the pause instruction **/ 
     sleep(5); 
     cout<<"Sleep completed now"<<endl; 
     /** Thread B has sent the signal; and it may be lost **/ 
     /** The pause will be blocked now, waiting for the signal to occur again **/ 
     rc = pause(); 
     cout<<"Unblocked now, the rc value is "<<rc<<endl; 

    } 

} 
} 


void *Thread_Function_B(void *thread_arg) 
{ 
    pthread_mutex_lock(&(helium_thread::mutex_thread)); 

    pid_B = getpid(); 

    cout<<"The pid value of Thread B is"<< pid_B << endl; 

    shared_variable = 5; 

    cout<<"Unblock the thread A now"<<endl; 

    pthread_kill(*(thread_1.get_thread_id()), SIGUSR1); 

    pthread_mutex_unlock(&(helium_thread::mutex_thread)); 
    cout<<"Return thread function b now"<<endl; 

} 

/** The definition of the static member can't be inside a function, You need to put it outside **/ 
/** When I tried using inside a function, I got the error - error: invalid use of qualified-name ‘helium_thread::mutex_thread **/ 

pthread_mutex_t helium_thread::mutex_thread = PTHREAD_MUTEX_INITIALIZER; 

int main(int argc, char *argv[]) 
{ 

    pid_t thread_pid_val = getpid(); 
    /** Install signal handler **/ 
    signal(SIGUSR1, handler);  
    thread_1.create_thread((thread_1.get_thread_id()),NULL,Thread_Function_A,&thread_pid_val); 
    thread_2.create_thread((thread_2.get_thread_id()),NULL,Thread_Function_B,&thread_pid_val); 
    pthread_join(*(thread_1.get_thread_id()), NULL); 
    pthread_join(*(thread_2.get_thread_id()), NULL); 

    return 0; 
} 

的輸出如下。

$ ./thread_basic.out 
Constructor called 0x1e01010 
Constructor called 0x1e01030 
Thread created 0x1e01010 
The pid value of Thread A is45a6 
Going to block now 
Thread created 0x1e01030 
The pid value of Thread B is45a6 
Unblock the thread A now 
Return thread function b now 
Handler called 
Sleep completed now 

回答

1

添加信號處理程序。

void handler(int sig) 
{ 
    //do nothing 
} 

設置從主(或地方)到趕上SIGUSR1(或類似)

signal(SIGUSR1, handler); 

ThreadB調用

pthread_kill(pthread_self(), SIGUSR1); 

信號處理程序將會運行,pause會醒來並返回-1並繼續。

這將工作,但仍然非常尷尬。

+0

謝謝,我應該實際上使用pthread_cond。我的目的是用這些代碼來證明競爭條件。這個問題實際上產生了一個解決方案 - cond_var。因此,有必要證明這個問題。我已經證明了這個問題。在代碼中查看我的意見。 –

+0

@SHREYAS JOSHI,我刪除了關於競賽情況的評論,因爲我並不是100%確定那是發生了什麼事情。我認爲@fibonacci遇到了這個問題。 'pause'只會從調用處理函數或終止進程的信號中返回。由於沒有處理程序,'SIGCONT'的默認值對於未關閉(而不是「已暫停」)過程是忽略信號,我認爲過程從未看到信號。如果你打算去追求它,可能會更值得玩一玩。 – Duck

+0

我從我的代碼中刪除了睡眠,我發現信號完全沒有被遺漏。編寫這個比賽條件程序的整個想法是爲了證明爲什麼需要條件變量。如果你在線程A中嘗試了第二個帶睡眠的程序,並在線程B中睡眠,你會看到信號有時會丟失,有時不會。因此,這個程序是不可靠的。這是一個很好的競爭條件的例子。 –

0
kill

將信號發送到過程和作爲輸出顯示,既你的線程屬於相同的處理。你需要使用pthread_kill或者linux專用的tkill或者使用pthread_sigmask來確保只有暫停的線程接收到SIGCONT信號。

1

您應該使用的pthread_t t_a = pthread_self()代替getpid()

而且pthread_kill(t_a , SIGCONT)代替kill

SIGCONT不僅延續的過程以前SIGSTOPSIGTSTP

所以停了下來,你可能會想嘗試:

pthread_kill(pthread_self(), SIGSTOP); 

而不是pause()

POSIX線程有條件變量的原因;使用它們...

+0

我現在正在做類似的東西,但它並沒有解鎖。現在檢查我的編輯。我現在改變了程序來調整pthread_kill。但是,它不會解除封鎖。 –

+0

man pause:暫停()會導致調用進程(或線程)進入休眠狀態,直到傳遞一個信號,該信號終止進程或導致調用信號捕獲函數。看我的編輯。 – fibonacci

+0

絕對不希望SIGSTOP在這裏。如果沒有弄錯,它會阻止整個過程和僵局。 – Duck