Спасибо, что сказали, чего вы на самом деле пытаетесь достичь.
Вам может оказаться гораздо проще создать один многопоточный процесс, чем создавать два однопоточных процесса.
Поток # 1 работает в цикле и периодически проверяет переменную exit_flag
. Если переменная установлена, то она вызывает exit
. Если он заканчивает работу, он вызывает exit
.
Тема # 2 ожидает ввода от пользователя. Если он получает ввод, он устанавливает переменную exit_flag
.
Таким образом, при вызове exit
оба потока автоматически завершатся. Вам нужно будет использовать мьютекс / семафор или другой вид синхронизации, например, если у вас libatomic-ops
:
#include "atomic_ops.h"
AO_t exit_flag;
// In thread #2
AO_store(&exit_flag, 1);
// In thread #1
while (!AO_load(&exit_flag)) {
...
}
Предупреждение о приведенном выше коде: Установка глобального флага работает только таким образом, поскольку основной поток only читает глобальный флаг и ничего больше. Если вы для передачи более одного слова между потоками вам понадобится какой-то механизм синхронизации, например мьютекс, семафор или AO_store_release
в паре с AO_store_acquire
.
Если вы используете процессы вместо потоков: Поскольку процессы не разделяют изменяемую память по умолчанию, это не так просто, как «обновление переменной». Каждый процесс имеет свой собственный набор личных переменных. Вам потребуется настроить область совместно используемой памяти или связаться каким-либо другим способом (например, сигнал, канал, сокет), что является дополнительной работой для вас.
Полный пример
Вот быстрый полный пример. Основной поток выполняет «работу», которая включает в себя обратный отсчет от 5. Когда он достигает 0, он выходит и печатает сообщение. Второй поток читает пользовательский ввод, когда он читает строку, начинающуюся с 'e'
, он устанавливает флаг, который вызывает выход основного потока.
Второй поток создается как отдельный поток только потому, что нам не нужно присоединяться к нему. Это не влияет на правильность этой конкретной программы.
Если вы вызываете exit
, , все потоки в вашей программе должны быть прерваны, если с вашей платформой что-то не так.
Примечание: В этом примере требуется libatomic-ops
и предполагается, что вы используете потоки POSIX.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <atomic_ops.h>
#include <errno.h>
static AO_t exit_flag;
#define fail(x) fail_func(x, __LINE__)
static void fail_func(int code, int line)
{
fprintf(stderr, "line %d: failed with code %d\n", line, code);
abort();
}
static void *input_thread(void *param)
{
char buf[16], *p;
(void) param;
while (1) {
p = fgets(buf, sizeof(buf), stdin);
if (!p)
break;
if (buf[0] == 'e')
break;
else
puts("unknown command");
}
AO_store(&exit_flag, 1);
return NULL;
}
int main(int argc, char *argv[])
{
pthread_attr_t attr;
pthread_t thread2;
int r, c;
struct timespec t;
t.tv_sec = 1;
t.tv_nsec = 0;
r = pthread_attr_init(&attr);
if (r) fail(r);
// Note: making the thread detached is not actually necessary.
r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (r) fail(r);
r = pthread_create(&thread2, &attr, input_thread, NULL);
if (r) fail(r);
c = 5;
while (1) {
if (AO_load(&exit_flag)) {
puts("thread 1 exiting (canceled)");
exit(1);
}
printf("counter = %d\n", c);
if (c == 0) {
puts("thread 1 exiting (finished)");
exit(0);
}
c--;
r = nanosleep(&t, NULL);
if (r) fail(errno);
}
return 0;
}
Пример вывода (пользовательский ввод полужирный ):
$ <b>./a.out</b>
counter = 5
counter = 4
counter = 3
counter = 2
counter = 1
counter = 0
thread 1 exiting (finished)
$ <b>./a.out</b>
counter = 5
counter = 4
<b>exit</b>
thread 1 exiting (canceled)