Как приостановить другой поток (не текущий)? - PullRequest
5 голосов
/ 05 февраля 2010

Я пытаюсь реализовать симуляцию микроконтроллера. Это моделирование не предназначено для точного представления тактового цикла одного конкретного микроконтроллера, но для проверки общей правильности кода.

Я думал о наличии "основного потока", выполняющего нормальный код, и второго потока, выполняющего код ISR. Всякий раз, когда требуется запустить ISR, поток ISR приостанавливает «основной поток».

Конечно, я хочу иметь возможность блокировать прерывания. Я думал о решении этого с мьютексом, который удерживает поток ISR всякий раз, когда он выполняет код ISR, в то время как основной поток удерживает его до тех пор, пока «прерывания заблокированы».

POR (сброс при включении питания) может быть реализован путем не только приостановки, но и уничтожения основного потока (и запуска нового, выполняющего функцию POR).

Windows API предоставляет необходимые функции. Но кажется, что это невозможно сделать с помощью потоков posix (в linux).

Я не хочу менять фактический аппаратно-независимый код микроконтроллера. Поэтому вставлять что-либо для проверки ожидающих прерываний не вариант.

Желательно получать прерывания в точках с плохим поведением, поскольку это также происходит на микроконтроллерах (если вы не блокируете прерывания).

Есть ли способ приостановить другой поток в Linux? (Я думаю, что отладчики должны использовать эту опцию.)

Пожалуйста, не говорите мне, что это плохая идея. Я знаю, что это правда в большинстве случаев. Но основной код не использует стандартные библиотеки libs или lock / mutexes / семафоры.

Ответы [ 6 ]

11 голосов
/ 02 ноября 2011

SIGSTOP не работает - он всегда останавливает весь процесс. Вместо этого вы можете использовать некоторые другие сигналы, например, SIGUSR1 для приостановки и SIGUSR2 для возобновления:

// at process start call init_pthread_suspending to install the handlers
// to suspend a thread use pthread_kill(thread_id, SUSPEND_SIG)
// to resume a thread use pthread_kill(thread_id, RESUME_SIG)

#include <signal.h>

#define RESUME_SIG SIGUSR2
#define SUSPEND_SIG SIGUSR1

static sigset_t wait_mask;
static __thread int suspended; // per-thread flag

void resume_handler(int sig)
{
    suspended = 0;
}

void suspend_handler(int sig)
{
    if (suspended) return;
    suspended = 1;
    do sigsuspend(&wait_mask); while (suspended);
}

void init_pthread_suspending()
{
    struct sigaction sa;

    sigfillset(&wait_mask);
    sigdelset(&wait_mask, SUSPEND_SIG)
    sigdelset(&wait_mask, RESUME_SIG);

    sigfillset(&sa.sa_mask);
    sa.sa_flags = 0;
    sa.sa_handler = resume_handler;
    sigaction(RESUME_SIG, &sa, NULL);

    sa.sa_handler = suspend_handler;
    sigaction(SUSPEND_SIG, &sa, NULL);
}

Меня очень раздражают ответы типа "Вы не должны приостанавливать другой поток, это плохо". Ребята, почему вы думаете, что другие идиоты и не знают, что они делают? Представьте, что другие тоже слышали о блокировке и все еще в полном сознании хотят приостановить другие потоки. Если у вас нет реального ответа на их вопрос, почему вы тратите свое время и время читателей.

Да, IMO pthreads - это очень близорукие API, позор для POSIX.

5 голосов
/ 08 февраля 2010

Виртуальная машина Hotspot JAVA использует SIGUSR2 для реализации приостановки / возобновления потоков JAVA в Linux.

Процедура, основанная на обработчике сигнала для SIGUSR2, может быть:

Предоставление обработчика сигнала для SIGUSR2 позволяет потоку запрашивать блокировку (который уже был получен потоком отправки сигнала).

Это приостанавливает поток.

Как только приостановившаяся нить снимает блокировку, обработчик сигнала может (и будет?) получить замок. Обработчик сигнала немедленно снимает блокировку и покидает обработчик сигнала.

Это возобновляет поток.

Вероятно, потребуется ввести управляющую переменную, чтобы убедиться, что основной поток находится в обработчике сигналов, прежде чем начинать фактическую обработку ISR. (Детали зависят от того, вызывается ли обработчик сигнала синхронно или асинхронно.)

Не знаю, так ли это на Java VM, но я думаю, что описанная выше процедура делает то, что мне нужно.

3 голосов
/ 06 февраля 2010

Каким-то образом я думаю, что отправка другого потока SIGSTOP работает.

Тем не менее, вам гораздо лучше написать какую-нибудь нить, включающую senaogires.mutexes и глобальные переменные.

Видите ли, если вы приостановили другой поток в malloc () и вызвали malloc () -> deadlock.

Я упоминал, что многие функции стандартной библиотеки C, не говоря уже о других используемых вами библиотеках, будут вызывать malloc () за вашей спиной?

EDIT:

Хммм, стандартного кода библиотеки нет. Возможно, используйте setjmp / longjump () из обработчика сигнала для имитации POR и обработчик сигнала для имитации прерывания.

ДЛЯ ЭТОГО, КОТОРЫЙ СОХРАНЯЕТ ЭТО: Ответ был принят для содержимого после РЕДАКТИРОВАНИЯ, что является специфическим сценарием, который нельзя использовать ни в каком другом сценарии.

1 голос
/ 06 февраля 2010

Имеет больше смысла, чтобы основной поток выполнял ISR - потому что именно так работает настоящий контроллер (предположительно). Просто проверяйте после каждой эмулируемой инструкции, есть ли ожидающие прерывания и включены ли прерывания в настоящий момент - если это так, эмулируйте вызов к ISR.

Второй поток по-прежнему используется - но он просто прослушивает условия, которые вызывают прерывание, и помечает соответствующее прерывание как ожидающее (для другого потока, чтобы позднее его обработать).

1 голос
/ 06 февраля 2010

У Solaris есть вызов thr_suspend (3C), который будет делать то, что вы хотите. Возможно ли переключиться на Solaris?

Кроме этого, вам, вероятно, придется заниматься гимнастикой с мьютексами и / или семафорами. Проблема в том, что вы будете приостанавливаться только тогда, когда проверяете мьютекс, который, вероятно, будет в хорошем состоянии. В зависимости от того, чего вы на самом деле пытаетесь достичь, это может быть желательно.

0 голосов
/ 07 февраля 2013

Решение с использованием сигналов pthread_kill (3) и SIGUSR1, SIGUSER2 является хорошим решением, но все же может вызвать проблему параллелизма. Есть ли способ приостановить все потоки (кроме основного потока) в безопасной точке, то есть во время приостановки потоки не должны были получить блокировку или не работать в системном вызове?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...