Почему sleep () в потоке не может быть прерван сигналом в моем коде? - PullRequest
0 голосов
/ 07 мая 2020
#include <iostream>
#include <thread>
#include <signal.h>
#include <unistd.h>

void handler(int sig){
  std::cout << "handler" << std::endl;
} 

void func() {
  sleep(100);
  perror("sleep err:");
}


int main(void) {
  signal(SIGINT, handler);
  std::thread t(func);
  pthread_kill(t.native_handle(), SIGINT);
  perror("kill err:");
  t.join();
  return 0;
}

Если я помещу sleep () в основную функцию и отправлю сигнал, нажав ctrl + c, сон будет прерван и немедленно вернется с perror (), сообщающим, что он прерван.

Но с код выше, "обработчик" в функции обработчика будет напечатан, но сон не вернется, и программа продолжит работу. Результатом этой программы будет:

kill err:: Success
handler

И если я заменю sleep () на recvfrom (), recvfrom () не будет прервана, даже если он находится внутри основного потока.

#include <vector>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <unistd.h>

void SigHandler(int sig){
  std::cout << "handler" << std::endl;
}

int main(void) {
 signal(SIGINT, SigHandler);
 int bind_fd_;
 if ((bind_fd_ = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    std::cout << "socket creation failed " << strerror(errno) << std::endl;
  }

  struct sockaddr_in servaddr;
  memset(&servaddr, 0, sizeof(servaddr));

  servaddr.sin_family = AF_INET;
  servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
  servaddr.sin_port = htons(12345);

  if (bind(bind_fd_, reinterpret_cast<const struct sockaddr *>(&servaddr),
           sizeof(servaddr)) < 0) {
    std::cout << "socket bind failed " << strerror(errno) << std::endl;
  }


  struct sockaddr_in cliaddr;    
  socklen_t cliaddr_len = sizeof(cliaddr);    
  std::vector<char> buffer(10*1024*1024,0);
  std::cout << "Wait for new request"<< std::endl;    
  int n = 0;    
  while (n == 0) {    
    std::cout << "before recvfrom" << std::endl;
    n = recvfrom(bind_fd_, buffer.data(), buffer.size(), 0,    
                 reinterpret_cast<struct sockaddr *>(&cliaddr), &cliaddr_len);    
    // sleep(100);
    perror("recvfrom err: ");
    std::cout << "recv " << n << " bytes from " << cliaddr.sin_port<< std::endl;    
  }    
}

Я не знаю, что не так с моим кодом, надеюсь на вашу помощь, спасибо

1 Ответ

0 голосов
/ 07 мая 2020

В то время, когда вы направляете сигнал в поток, этот поток еще не прошел достаточно далеко, чтобы заблокироваться в sleep (). Скорее всего, это даже не запланировано впервые. Измените код на что-то вроде

std::thread t(func);
sleep(5); // give t enough time to arrive in sleep()
pthread_kill(t.native_handle(), SIGINT);

, и вы увидите то, что ожидаете.

Обратите внимание, что использование сигналов в многопоточной программе обычно не является хорошей идеей, поскольку некоторые аспекты не определены / не так четко определено.

Обратите внимание, что использовать iostreams внутри обработчика сигнала неправильно. Обработчики сигналов работают в контексте, в котором практически ничего нельзя делать безопасно, во многом как подпрограмма обслуживания прерывания на голом железе. См. здесь для более подробного объяснения этого вопроса.

...