2014-01-05 22 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