Принудительно заблокировать системный вызов другого потока для возврата и установить для errno значение EINTR - PullRequest
0 голосов
/ 06 августа 2020

, пожалуйста, просмотрите следующий пример исходного кода:

void tfunc()
{
    // Some blocking syscall that sets errno
    if (errno == EINTR)
   {
        std::cout << "cleanup" << std::endl;
       return;
   }
   // Do some other stuff
}

int main(int argc, char *argv[])
{
    std::thread t(tfunc);
    sleep(10);
    return 0;
}

Возможно ли из другого потока иметь системный вызов, например accept(), чтобы вернуть и установить errno на EINTR? Если да, то как?

1 Ответ

1 голос
/ 07 августа 2020

Предлагаю вам использовать:

  • неблокирующие операции
  • poll() (или select() или epoll())
  • трубу

Перед тем, как создать поток, вы устанавливаете канал, который будет передавать «сообщение о прерывании». В вашем потоке tfunc вы устанавливаете poll так, чтобы он ждал как файловый дескриптор (сокет), с которым вы хотите работать, , так и читаемый конец канала.

Если вы хотите прервать, просто написав «сообщение прерывания» в конец канала записи; и в потоке проверьте при возврате poll, есть ли в канале данные для чтения.

Небольшая демонстрация, без обработки ошибок, без обработки сигналов, просто чтобы визуализировать, что я имею в виду:

#include <cassert>
#include <iostream>
#include <thread>


#include <poll.h>
#include <unistd.h>

int fd[2];

void the_blocking_thread(void)
{
    pollfd pollfds[2];
    pollfds[0].fd = fd[0];
    pollfds[0].events = POLLIN;
    pollfds[1].fd = -99; // add here your socket / fd
    pollfds[1].events = POLLIN; // or whatever you need
    std::cout << "waiting for \"interrupt message\" or real work on fd" << std::endl;
    int ret = poll(pollfds, 2, -1);
    assert(ret > 0);
    if (pollfds[0].revents != 0) {
        std::cout << "cleanup" << std::endl;
        return;
    }
    // Non blocking call on your fd
    // Some other stuff
}


int main() {
    int ret = pipe(fd);
    assert(ret == 0);
    std::cout << "Starting thread" << std::endl;
    std::thread t(the_blocking_thread);
    std::chrono::seconds timespan(1); // or whatever
    std::this_thread::sleep_for(timespan);
    std::cout << "Sending \"interrupt\" message" << std::endl;
    char dummy = 42;
    ret = write (fd[1], &dummy, 1);
    assert(ret == 1);
    t.join();
}

( Живое )

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...