Страницы

Поиск по вопросам

понедельник, 19 ноября 2018 г.

Блокировать процесс пока не завершатся потоки/дочерние процессы

Есть такой код:
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 #include #include #include #include #include #include #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 processes; for (unsigned i = 0; i < 10; ++i) { fork_storage fork_obj; if (fork_obj.fail()) { std::cerr << "fork error
"; } 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

Комментариев нет:

Отправить комментарий