Есть такой код:
if(pid_t pid = fork()) // spawn child process
{
// parent process
LOG("Try to execute smth. in child process");
return;
}
else
{
// child process
doWork();
std::terminate();
}
Тут порождается дочерний процесс в котором выполняется некоторая работа. Где-то в другом месте(а именно в момент завершения процесса) есть такое:
// wait childern(some code may call fork())
const pid_t pid{::wait(nullptr)};
Здесь процесс ждет завершения дочерних процессов(которые нафоркались ранее). Так вот, все это удовольствие не работает вместе ключом -fsanintize=thread. Код зависает на wait, потому что компилятор добавляет некоторые дочерние процессы, которые сами не завершаются.
Вопрос. Как добиться аналогичного поведения без wait? Чтобы задачи запускались асинхронно, и главный процесс ждал завершения этих задач в случае прекращения работы. Может при помощи потоков, а не процессов. Если бы у меня в распоряжении был Qt, я бы закидывал эти doWork в QThreadPool и он бы в декструкторе ждал завершения всех задач. Но Qt у меня нет, а есть C++14 и pthread. Может кто-то предложить какое-нибудь решение?
Ответ
Накидал на скорую руку, но, думаю, идея понятна.
#include
class fork_storage
{
public:
fork_storage() noexcept
{
m_pid = fork();
}
fork_storage(const fork_storage&) = delete;
fork_storage& operator=(const fork_storage&) = delete;
fork_storage& operator=(fork_storage&& rhv) = delete;
fork_storage(fork_storage&& src) noexcept
{
m_pid = src.pid();
src.reset();
}
~fork_storage()
{
if (is_parent()) {
wait();
}
}
bool fail() const noexcept
{
return m_pid < 0;
}
bool is_parent() const noexcept
{
return m_pid > 0;
}
void reset() noexcept
{
m_pid = -1;
}
pid_t pid() const noexcept
{
return m_pid;
}
int wait() noexcept
{
int status = -1;
if (is_parent()) {
waitpid(m_pid, &status, WUNTRACED);
}
reset();
return status;
}
private:
pid_t m_pid;
};
std::mt19937 &random_gen()
{
static std::mt19937 gen(std::chrono::system_clock::now().time_since_epoch().count());
return gen;
}
int main()
{
std::vector
";
} else {
if (fork_obj.is_parent()) {
std::string message = "process created: " + std::to_string(fork_obj.pid()) + "
";
processes.emplace_back(std::move(fork_obj));
} else {
for (auto &process: processes) {
process.reset();
}
processes.clear();
std::chrono::seconds sec(random_gen()() % 5 + 1);
std::string message = "child " + std::to_string(getpid()) + " paused: " + std::to_string(sec.count()) + " sec
";
std::cout << message;
std::this_thread::sleep_for(sec);
break;
}
}
}
while (!processes.empty()) {
fork_storage &fork_obj = processes.back();
if(fork_obj.is_parent()) {
std::string message = "wait process: " + std::to_string(fork_obj.pid()) + "
";
std::cout << message;
}
processes.pop_back();
}
}
http://rextester.com/LUZI37730
Комментариев нет:
Отправить комментарий