Теперь это исправлено. Я добавил еще одну программу, чтобы показать, как она исправлена. Эта программа должна продемонстрировать, как сигналы теряются в многопоточной среде. Эта потеря сигнала вызывает состояние гонки. Блокирующая нить никогда не получает сигнал для разблокирования, поскольку он пропускает сигнал. Это условие и мьютекс. Решением этой проблемы является использование cond_var. Cond_var защищает состояние, а также данные. Таким образом, он автоматически блокирует условие, и он разблокирует условие, как только он сигнализирует об этом другой поток. Блокировка состояния защищает его от пропусков сигнала. Здесь добавлена неисправная программа - программа состояния гонки.
У меня есть следующая программа. Я пытаюсь разблокировать его при вызове-kill. Но моя программа зависает, потому что она никогда не посылает сигнал заблокированной функции(). Я не хочу использовать 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
------------------Working Гонка - Состояние program-
#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
Добавьте обработчик сигнала.
void handler(int sig)
{
//do nothing
}
Установите его из основного (или где-нибудь), чтобы поймать SIGUSR1 (или аналогичный)
signal(SIGUSR1, handler);
Режимы ThreadB
pthread_kill(pthread_self(), SIGUSR1);
Обработчик сигнала будет запущен, pause
запустится и вернет -1 и продолжит работу.
Это будет работать, но все еще очень неудобно.
Вы должны использовать pthread_t t_a = pthread_self()
вместо getpid()
И pthread_kill(t_a, SIGCONT)
вместо того, чтобы kill
SIGCONT только продолжает процесс, ранее остановленный SIGSTOP
или SIGTSTP
Итак, вы можете попробовать:
pthread_kill(pthread_self(), SIGSTOP);
Вместо pause()
Потоки POSIX имеют условные переменные по какой-либо причине; используй их...
kill
посылает сигналы процессам и, как показывает ваш вывод, оба ваши потоки относятся к одному и тому же процессу. Вам нужно будет использовать pthread_kill
или конкретный linux tkill
или беспорядок вокруг с pthread_sigmask
чтобы гарантировать, что только приостановленный поток получает сигнал SIGCONT.
pause
будет возвращаться только из сигнала, который вызывает обработчик или завершает процесс. Поскольку не было никакого обработчика иSIGCONT
умолчанию для неостановленного (в отличие от «приостановленного») процесса заключается в игнорировании сигнала, я думаю, что процесс вообще никогда не видел сигнал. Возможно, стоит потренироваться немного больше, если вы собираетесь продолжить.