2015-04-28 3 views
2

У меня проблема с вилкой, которая возникает только эпизодически. Он работает в основном все время, но не каждый раз в тестовой системе.Linux, разветвленный процесс зависает сразу

Мое исследование не привлекло никого, кто упомянул об аналогичной проблеме.

Проблема возникает во встроенной системе Linux. Доступны разделы подкачки.

Выполнение процесса блокирует все сигналы во всех потоках и обрабатывает их через sigtimedwait в выделенном потоке.

Если я начинаю дочерний процесс с помощью вилки:

  • Родительский процесс продолжается с возвращаемым значением> 0. Таким образом, вилка работает. Существует нет -1 возвращено - поэтому никаких ошибок, а не из памяти! Затем родитель ждет дочернего процесса и никогда не возвращается из ожидания.
  • Детский процесс никогда ничего не делает наблюдаемый. Самое первое, что дочерний процесс должен сделать, пишет сообщение журнала. Это сообщение журнала никогда не появляется. Затем он должен порождать два ребенка: обрабатывает процесс тайм-аута и рабочий процесс. Эти процессы никогда не появляются.
  • Если я проверил через ps в командной строке, я вижу существующий дочерний процесс. Он находится в состоянии S (Прерывающий сон (ожидание завершения события)). Он никогда не получает никакого процессорного времени, он не показывает использования ЦП.
  • Если я убить -9 дочерний процесс, родительский процесс заканчивается, ожидая и продолжает счастливо.

Псевдо код, показывающий проблему:

const pid_t childPid = fork(); 
if(0 == childPid) { 
    // child process 
    LOG_MSG("Child process started."); // <- This never shows up in the syslog. 

    // do some stuff 

} else if(-1 == childPid) { 
    // error 
    LOG_MSG("Parent process: Error starting child process!"); 
    result = false; 
} else { 
    // parent process 
    LOG_MSG("Parent process: Child process started. PID: %.", childPid); // <- This shows up in the syslog. 

    // do some stuff 
    int status = 0; 
    const int options = 0; 
    const auto waitResult = waitpid(childPid, &status, options); 
    // more stuff 
} 

Вопросы:

  1. Что может вызвать этот процесс ребенок висит?
  2. Что произойдет, если новый процесс закончится из памяти в вызове LOG_MSG, который приводит к syslog? Это поднимет сигнал (который не может быть доставлен, потому что он заблокирован)?
+0

Родитель процесса не ждет acutally – hek2mgl

+4

Каково определение 'LOG_MSG'? – PSkocik

+3

Можете ли вы запустить свою программу с помощью «strace», используя опцию «-ff», чтобы следовать за forks? например «strace -o output.txt -ff your_program». Вы должны увидеть файл трассировки для родительского процесса и любого дочернего элемента, который он порождает. Информация в этих файлах может быть освещена. –

ответ

3

Я взял образец из Adrien Descamps' link (см также комментарии выше) и C++ - маньяков и изменил его немного:

#include <thread> 
#include <iostream> 
#include <atomic> 

#include <unistd.h> 
#include <syslog.h> 
#include <sys/wait.h> 


std::atomic<bool> go(true); 


void syslogBlaster() { 
    int j = 0; 
    while(go) { 
     for(int i = 0; i < 100; ++i) { 
     syslog(LOG_INFO, "syslogBlaster: %[email protected]%d", i, j); 
     } 
     ++j; 

     std::this_thread::sleep_for(std::chrono::milliseconds(30)); 
    } 
} 

int main() { 
    std::thread blaster(syslogBlaster); 

    for(int i = 0; i < 1000; ++i) { 
     const auto forkResult = fork(); 
     if(0 == forkResult) { 
      syslog(LOG_INFO, "Child process: '%d'.", static_cast<int>(getpid())); 
      exit(0); 
     } else if(forkResult < 0) { 
     std::cout << "fork() failed!" << std::endl; 
     } else { 
     syslog(LOG_INFO, "Parent process."); 
     std::cout << "Waiting #" << i << "!" << std::endl; 
     int status = 0; 
     const int options = 0; 
     const auto waitResult = waitpid(forkResult, &status, options); 
     if(-1 == waitResult) { 
      std::cout << "waitpid() failed!"; 
     } else { 
      std::cout << "Bye zombie #" << i << "!" << std::endl; 
     } 
     } 

     std::this_thread::sleep_for(std::chrono::milliseconds(28)); 
    } 

    go = false; 
    blaster.join(); 

    std::cout << "Wow, we survived!" << std::endl; 
} 

Запуск этого примера, процесс застревает (на устройстве) между первая и пятая попытки.

Объяснение

Syslog проблема!

В общем: не являющиеся асинхронный сигнал безопасных функций являются проблемой!

Как заявила Damian Pietras (см связаны страницы)

вызова какой-либо функции, которая не является асинхронным безопасным (человек 7 сигнала) в ребенке процесса после вилки вызова() в многопоточной программе есть не определено поведение

Технически задача (неопределенное поведение) возникает из данных в критических секциях, которые не согласуются (так как поток, который является не один разветвлением был прямо в середине его во время вилки) или -как в этом случае, - из мьютекса, который был заперт в родительском, а затем остается таким образом навсегда у ребенка.

Кредит за этот ответ адресован Адриен Декамп для поиска первопричины (syslog), а также для PSkocik и Jan Spurny для обнаружения источника (LOG_MSG).

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