Как передать сигнал, чтобы разблокировать pause () в Linux?

0

Теперь это исправлено. Я добавил еще одну программу, чтобы показать, как она исправлена. Эта программа должна продемонстрировать, как сигналы теряются в многопоточной среде. Эта потеря сигнала вызывает состояние гонки. Блокирующая нить никогда не получает сигнал для разблокирования, поскольку он пропускает сигнал. Это условие и мьютекс. Решением этой проблемы является использование 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
Теги:
multithreading
pthreads
posix

3 ответа

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 умолчанию для неостановленного (в отличие от «приостановленного») процесса заключается в игнорировании сигнала, я думаю, что процесс вообще никогда не видел сигнал. Возможно, стоит потренироваться немного больше, если вы собираетесь продолжить.
Показать ещё 2 комментария
1

Вы должны использовать pthread_t t_a = pthread_self() вместо getpid()

И pthread_kill(t_a, SIGCONT) вместо того, чтобы kill

SIGCONT только продолжает процесс, ранее остановленный SIGSTOP или SIGTSTP

Итак, вы можете попробовать:

pthread_kill(pthread_self(), SIGSTOP);

Вместо pause()

Потоки POSIX имеют условные переменные по какой-либо причине; используй их...

  • 0
    Я делаю подобные вещи сейчас, но это не разблокирует. Проверьте мое редактирование сейчас. Я изменил программу сейчас, чтобы настроить pthread_kill. Но, это не разблокирует.
  • 0
    man pause: pause () заставляет вызывающий процесс (или поток) спать до тех пор, пока не будет доставлен сигнал, который либо завершит процесс, либо вызовет функцию перехвата сигнала. Смотрите мое редактирование.
Показать ещё 1 комментарий
0

kill посылает сигналы процессам и, как показывает ваш вывод, оба ваши потоки относятся к одному и тому же процессу. Вам нужно будет использовать pthread_kill или конкретный linux tkill или беспорядок вокруг с pthread_sigmask чтобы гарантировать, что только приостановленный поток получает сигнал SIGCONT.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню