Я много борюсь с многопроцессорностью / многопоточностью / подпроцессингом. В основном я пытаюсь выполнить каждый двоичный файл, доступный на моем компьютере, для этого я написал скрипт python. Но у меня продолжают происходить процессы зомбирования ie («несуществующие»), которые оказываются в тупике, если все 4 моих работника находятся в этом состоянии. Я пробовал много разных вещей, но, похоже, ничего не получается: (
Вот как выглядит архитектура:
| \_ python -m dataset --generate
| \_ worker1
| | \_ [thread1] firejail bin1
| \_ worker2
| | \_ [thread1] firejail bin1
| | \_ [thread2] firejail bin2
| | \_ [thread3] firejail bin3
| \_ worker3
| | \_ [thread1] [firejail] <defunct>
| \_ worker4
| | \_ [thread1] [firejail] <defunct>
4 рабочих я создаю так:
# spawn mode prevents deadlocks https://codewithoutrules.com/2018/09/04/python-multiprocessing/
with get_context("spawn").Pool() as pool:
results = []
for binary in binaries:
result = pool.apply_async(legit.analyse, args=(binary,),
callback=_binary_analysis_finished_callback,
error_callback=error_callback)
results.append(result)
(заметьте, я использую пул "spawn", но теперь мне интересно, пригодится ли он ...)
Каждый работник создаст несколько потоков, например:
threads = []
executions = []
def thread_wrapper(*args):
flows, output, returncode = _exec_using_firejail(*args)
executions.append(Execution(*args, flows, is_malware=False))
for command_line in potentially_working_command_lines:
thread = Thread(target=thread_wrapper, args=(command_line,))
threads.append(thread)
thread.start()
for thread in threads:
thread.join()
И каждый поток запускает новый процесс в изолированной программной среде firejail:
process = subprocess.Popen(FIREJAIL_COMMAND +
["strace", "-o", output_filename, "-ff", "-xx", "-qq", "-s", "1000"] + command_line,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, preexec_fn=os.setsid)
try:
out, errs = process.communicate(timeout=5, input=b"Y\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\nY\n")
# print("stdout:", out)
# print("stderr:", errs)
except subprocess.TimeoutExpired:
# print(command_line, "timed out")
os.killpg(os.getpgid(process.pid), signal.SIGKILL)
out, errs = process.communicate()
Я использую os.killpg()
, а не process.kill()
, потому что по некоторым причинам подпроцессы моего процесса Popen не уничтожаются. .. Это возможно благодаря preexec_fn=os.setsid
, который устанавливает gid всех потомков, но даже при использовании этого метода некоторые процессы, такие как zsh, будут вызывать процесс zomb ie, потому что, похоже, zsh меняет свой gid и поэтому мой os.killpg
не работает должным образом ...
Я ищу способ на 100% быть уверенным, что все процессы будут мертвы.