2016-12-11 16 views
4

Я пытаюсь подождать waitpid() и read() в цикле while-true. В частности, я жду одного из этих двух событий, а затем обработаю его на каждой итерации цикла. В настоящее время у меня есть следующая реализация (чего я не хочу).Как подождать 2 типа событий в цикле (C)?

while (true) { 
    pid_t pid = waitpid(...); 
    process_waitpid_event(...); 

    ssize_t sz = read(socket, ....); 
    process_read_event(...); 
} 

Проблема с этой реализацией заключается в том, что обработка второго события зависит от завершения первого события. Вместо того, чтобы обрабатывать эти два события последовательно, я хочу обработать любое событие, которое будет первым в каждой итерации цикла. Как мне это сделать?

+0

Вы хотите сделать это асинхронным способом? –

+1

Это больше похоже на проблему с потоками. Вы можете найти, как потоки могут быть реализованы в C. –

+0

Просьба подробно остановиться на вашей проблеме. Что за ожидание и от чего вы читаете. В частности, есть ли случай, когда вы просто имеете один дочерний процесс и хотите прочитать его вывод, но просто нужно знать, когда он закончится? –

ответ

3

Если вы не хотите, чтобы коснуться нарезание резьбы, вы можете включить его в настройках вызова waitpid:

pid_t pid = waitpid(pid, &status, WNOHANG); 

Как от страницы руководства для waitpid:

WNOHANG - возвращение немедленно, если ребенок не вышел.

Как таковой, если waitpid не готов, он не будет блокироваться, и программа будет просто продолжать переход к следующей строке.

Что касается read, если это блокировка, вы можете взглянуть на poll(2). Вы можете по существу проверить, готов ли ваш сокет к каждому установленному интервалу, например. 250 мс, а затем позвоните по телефону read. Это позволит ему не блокировать.

Ваш код может выглядеть немного так:

// Creating the struct for file descriptors to be polled. 
struct pollfd poll_list[1]; 
poll_list[0].fd = socket_fd; 
poll_list[0].events = POLLIN|POLLPRI; 
// POLLIN There is data to be read 
// POLLPRI There is urgent data to be read 

/* poll_res > 0: Something ready to be read on the target fd/socket. 
** poll_res == 0: Nothing ready to be read on the target fd/socket. 
** poll_res < 0: An error occurred. */ 
poll_res = poll(poll_list, 1, POLL_INTERVAL); 

Это только при условии, что вы read ИНГ из сокета, судя по именам переменных в вашем коде. Как говорили другие, ваша проблема может потребовать чего-то более тяжелого режима, такого как резьба.

+0

Можете ли вы объяснить, почему вы предлагаете что-то подобное, а не обрабатывать SIGCHLD? –

+0

Поскольку пользователь изначально использовал waitpid, а не обрабатывал сигналы, хотя это, конечно же, было бы правильным вариантом, учитывая, что их программа ждет дочернего процесса. –

+0

cmon. Установка обработчика SIGCHLD и обработка EINTR из чтения - это стандартная вещь, которая подходит в большинстве случаев. Решение, предложенное ниже, в том, что оно добавляет больше циклов к петле и заставляет поток просыпаться, даже когда ему нечего делать. Что еще более важно, однако, очень неясно, есть ли у ОП какая-то причина для ожидания в петле в первую очередь. Скорее всего, они просто породили ребенка и просто хотят прекратить чтение после его выхода. Решение состоит в том, чтобы просто продолжать чтение до тех пор, пока не останется ничего, и после этого вы получите статус выхода с waitpid. –

1

Ответ @DanielPorteous должен работать, если вы не хотите использовать поток в своей программе.

Идея проста, не сохраняя функции waitpid и read, чтобы ждать, если они не потратят некоторое время на выполнение своей работы. Идея заключается в том, чтобы сохранить механизм тайм-аута, чтобы, если waitpid не имеет ничего, чтобы создать воздействие на всю операцию, он немедленно вернется, и то же самое произойдет и для операции чтения.

Если функция read занимает очень много времени, чтобы прочитать весь буфер, вы можете ограничить чтение вручную из функции read, чтобы она не читала целое сразу, а читала ее в течение 2 миллисекунд, а затем передавала цикл до функции waitpid для выполнения.

Но его безопасно использовать резьбу для вашей цели и ее довольно легко реализовать. Here's a nice guideline о том, как вы можете реализовать потоки.

В вашем случае вам нужно объявить два потока.

pthread_t readThread; 
pthread_t waitpidThread; 

Теперь вам нужно создать поток и передать определенную функцию в качестве параметра.

pthread_create(&(waitpidThread), NULL, &waitpidFunc, NULL); 
pthread_create(&(readThread), NULL, &readFunc, NULL); 

Теперь вы, возможно, придется написать waitpidFunc и readFunc функцию. Они могут выглядеть так.

void* waitpidFunc(void *arg) 
{ 
    while(true) { 
     pid_t pid = waitpid(...); 

     // This is to put an exit condition somewhere. 
     // So that you can finish the thread 
     int exit = process_waitpid_event(...); 

     if(exit == 0) break; 
    } 

    return NULL; 
} 
0

Я думаю, что правильный инструмент в этой ситуации select или poll. Оба выполняют практически ту же работу. Они позволяют выбирать те дескрипторы, в которых доступен вход. Следовательно, вы можете подождать одновременно на двух сокетах, например. Однако он не может использоваться непосредственно в вашем случае, так как вы хотите дождаться процесса и сокета. Решением будет создание трубы, которая будет получать что-то, когда заканчивается waitpid.

Вы можете запустить новую резьбу и подключить ее к оригинальной трубе. Новый поток будет вызывать waitpid, и когда он закончит, он напишет свой результат на трубу. Основной поток будет ждать либо для сокета, либо для канала, используя select.

+0

Извините мое невежество, вы можете сравнить это с использованием SIGCHLD? То, что вы представляете, кажется, значительно больше связано и не дает никакой пользы, которую я бы увидел. Также неясно, нуждается ли OP в чем-то в своем роде, есть хорошие шансы, что на самом деле у них есть труба, и просто нужно дождаться, когда она закроется, после чего точка может просто ждать, чтобы получить статус выхода. –

 Смежные вопросы

  • Нет связанных вопросов^_^