Функция, которая принимает pthread в качестве ввода и приостанавливает его
Я пытаюсь портировать Thread_Metric в реальном времени из ExpressLogic в POSIX, чтобы сравнить патчи PREEMPT_RT для Linux, Xenomai и RTAI для моей диссертации. Они предоставляют исходный файл C со следующими функциями, которые вы должны реализовать, чтобы тест работал:
void tm_initialize(void (*test_initialization_function)(void));
int tm_thread_create(int thread_id, int priority, void (*entry_function)(void));
int tm_thread_resume(int thread_id);
int tm_thread_suspend(int thread_id);
void tm_thread_relinquish(void);
void tm_thread_sleep(int seconds);
int tm_queue_create(int queue_id);
int tm_queue_send(int queue_id, unsigned long *message_ptr);
int tm_queue_receive(int queue_id, unsigned long *message_ptr);
int tm_semaphore_create(int semaphore_id);
int tm_semaphore_get(int semaphore_id);
int tm_semaphore_put(int semaphore_id);
int tm_memory_pool_create(int pool_id);
int tm_memory_pool_allocate(int pool_id, unsigned char **memory_ptr);
int tm_memory_pool_deallocate(int pool_id, unsigned char *memory_ptr);
Сейчас я пытаюсь реализовать функции tm_thread_suspend и tm_thread_resume, которые принимают pthread в качестве входных данных. Я знаю, что вы можете приостановить pthread с помощью процедур pthread_mutex_lock и pthread_cond_wait, но вы должны вызывать их из потока start_function. Я новичок в такого рода вещах, и я над головой. Любая помощь приветствуется.
4 ответа
pthread_suspend
действительно кажется, что путь, если он доступен. Это решение может быть более грязным, чем оно того стоит. Для каждого потока сохраните semaphore
, Сделайте так, чтобы каждый поток слушал сигналы. В обработчике сигнала просто сделайте down
на связанном семафоре.
Поэтому, когда вы хотите stop
поток, просто отправьте ему сигнал (возможно, лучше использовать сигнал в реальном времени), и он остановится в обработчике. По умолчанию обработчик маскирует себя (то есть он больше не будет вызываться, если тот же сигнал будет получен до того, как это будет сделано). Если вы хотите перезапустить поток, просто выполните up
на семафор.
Предостережение:
- Используйте то, что предлагает @bmargulies, лучше (безопаснее, чище, эффективнее), если вы можете
- Вы также можете использовать мьютекс вместо семафора
- Работа с сигналами - неприятная работа. Прежде чем приступить к работе, убедитесь, что вы (пере) прочитали о
- Асинхры-сигнал безопасность
- темы и сигналы
- прерывание и перезапуск системных вызовов (
SA_RESTART
)
- я весьма уверен
sem_wait(3)
не асинхронный сигнал безопасен, но он безопасен, если вы не используетеSA_NODEFER
(не то чтобы у тебя была какая-либо причина)
К сожалению, я не могу найти действительно звездную бесплатную документацию по этому поводу. Тем не менее, звездные или нет, есть много бесплатной документации.
редактировать
Как предполагает @R.. есть async-signal-safe
функции, которые блокируют, что вы можете использовать (вместо небезопасных sem_wait
). Вот список функций, которые вы можете безопасно использовать.
Некоторые реализации pthreads имеют эти функции. http://www.unix.com/man-page/all/3t/pthread_suspend/ Но ваше ядро Linux может не поддерживать их.
Вы можете сделать это полностью переносимо (избегая всех проблем с функциями async-signal-unsafe), используя два сигнала:
Обработчик сигнала "Thread Suspend" будет использовать pselect
атомно разблокировать второй сигнал и спать бесконечно. Второй сигнал завершит pselect
и заставить обработчик сигнала вернуться.
Также существует множество других решений, использующих асинхронно-безопасные интерфейсы - в основном все, что связано с файловыми дескрипторами и их блокировкой, а не с примитивами синхронизации в пользовательском пространстве. Например, имея обработчик сигнала read
из канала и запись одного байта в канал для возобновления потока будет работать.
Чтобы сделать это, используйте sigwait() и pthread_kill.
// глобальная переменная
int _fSigSet;
Перед вызовом pthread_create мы устанавливаем маску сигнала. Каждый поток унаследует маску. Вы могли бы установить маску в функции потока, я полагаю. Вот код, который мы используем:
sigemptyset(&_fSigSet);
sigaddset(&_fSigSet, SIGUSR1);
sigaddset(&_fSigSet, SIGSEGV);
pthread_sigmask(SIG_BLOCK, &_fSigSet, NULL);
...
pthread_create(&Thread, NULL, ThreadProc, NULL);
...
Приостановить:
int nSig; // signal you get if you care.
sigwait(&_fSigSet, &nSig); // thread is suspended here waiting for signal.
Возобновить:
pthread_kill(&Thread, SIGUSR1);
Если по какой-то причине вы не можете использовать SIGUSR1, знайте, что не все сигналы работают для нас. Мы можем делать что-то не так, но SIGCONT не работает.
Таким образом, мы тестировали приостановку потоков, и этот метод был в 5 раз быстрее, чем использование мьютексов и условных переменных.
Вот некоторый код, который использует эту технику.