Функция, которая принимает 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_mutex_lock и pthread_cond_wait, но вы должны вызывать их из функции start_function потока. Я новичок в таких вещах, и я вхожу в заблуждение. Любая помощь приветствуется.


person ody    schedule 20.04.2011    source источник


Ответы (4)


pthread_suspend действительно кажется подходящим вариантом, если он доступен. Это решение может быть более грязным, чем оно того стоит. Для каждого потока сохраните semaphore. Заставьте каждый поток прослушивать сигналы. В обработчике сигналов просто выполните down для связанного семафора.

Поэтому, когда вы хотите stop поток, просто отправьте ему сигнал (возможно, лучше всего будет использовать сигнал в реальном времени), и он остановится в обработчике. Обработчик маскирует себя по умолчанию (то есть он не будет вызываться снова, если тот же сигнал будет получен до его выполнения). Если вы хотите перезапустить поток, просто сделайте up на семафоре.

Предостережение:

  • Используйте то, что предложил @bmargulies, это лучше (безопаснее, чище, эффективнее), если можете
  • Вы также можете использовать мьютекс вместо семафора
  • Dealing with signals is a nasty job. Before embarking make sure you (re)read about
    • async-signal-safety
    • потоки и сигналы
    • прерывание и перезапуск системных вызовов (SA_RESTART)
  • Я почти уверен, что sem_wait(3) небезопасен для асинхронных сигналов. , но это безопасно, если вы не используете SA_NODEFER (не то чтобы у вас была какая-то причина)

К сожалению, я не могу найти действительно звездную бесплатную документацию по этому поводу. Тем не менее, звездная или нет, есть много бесплатной документации.

Изменить

Как предложил @R.., есть async-signal-safe функций, которые блокируют, которые вы могли бы использовать (вместо небезопасных sem_wait). Вот список функций, которые вы можете безопасно использовать.

person cnicutar    schedule 20.04.2011
comment
У вас правильный подход, но вам нужны функции, безопасные для асинхронных сигналов, в обработчике сигналов. Мой ответ обрисовывает некоторые идеи. - person R.. GitHub STOP HELPING ICE; 21.04.2011
comment
@R.. Это отличная идея. Я вижу, что SUSv3 указывает pselect(2) как безопасный асинхронный сигнал, что решит проблемы с этим подходом. - person cnicutar; 21.04.2011

Вы можете сделать это полностью переносимо (избегая всех проблем с небезопасными функциями асинхронного сигнала), используя два сигнала:

Обработчик сигнала «приостановка потока» будет использовать pselect для атомарной разблокировки второго сигнала и бездействия на неопределенный срок. Второй сигнал завершит pselect и вызовет возврат обработчика сигнала.

Также существует множество других решений, использующих безопасные для асинхронных сигналов интерфейсы — в основном все, что связано с дескрипторами файлов и их блокировкой, а не с примитивами синхронизации в пользовательском пространстве. Например, будет работать обработчик сигнала read из канала и запись одного байта в канал для возобновления потока.

person R.. GitHub STOP HELPING ICE    schedule 20.04.2011

Некоторые реализации pthreads имеют эти функции. http://www.unix.com/man-page/all/3t/pthread_suspend/ Но ваше ядро ​​Linux может их не поддерживать.

person bmargulies    schedule 20.04.2011
comment
pthread_suspend - это не функция pthread, это расширение поставщика. - person R.. GitHub STOP HELPING ICE; 21.04.2011
comment
'pthread_suspend() и pthread_continue() были разработаны X/Open.' - person bmargulies; 21.04.2011
comment
И еще не входит в стандарт. Вероятно, вы сможете порыться в документах с обоснованием и найти довольно вескую причину. - person R.. GitHub STOP HELPING ICE; 21.04.2011

Это можно сделать с помощью 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 раз быстрее, чем использование мьютексов и условных переменных.

Вот некоторый код, в котором используется этот метод.

person johnnycrash    schedule 25.04.2011