我遇到了叉子的问题,只是偶尔发生。它基本上一直有效,但在测试系统中偶尔会失败。
我的研究并没有提到任何提到类似问题的人。
问题出现在嵌入式Linux系统上。没有可用的交换分区。
正在运行的进程在所有线程中阻塞所有信号,并通过专用线程中的sigtimedwait处理它们。
如果我通过fork启动子进程:
显示问题的伪代码:
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
}
问题:
答案 0 :(得分: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: %d@%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所述(见链接页面)
在子节点中调用任何非异步安全的函数(man 7 signal) fork()调用多线程程序后的进程是未定义的 行为
从技术上讲,问题(未定义的行为)是由于关键部分中的数据不一致(因为不是一个分叉的线程在分叉期间正好位于它的中间)或者 - 就像在这种情况下 - 来自锁定在父级中的互斥锁,然后永远保持在子级中。
这个答案归功于Adrien Descamps找到根本原因(系统日志),还有PSkocik和Jan Spurny检测源(LOG_MSG)。