Функция, которая принимает pthread в качестве ввода и приостанавливает его - PullRequest
3 голосов
/ 21 апреля 2011

Я пытаюсь портировать 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 ]

3 голосов
/ 21 апреля 2011

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

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

Предупреждение:

  • Используйте то, что предлагает @bmargulies, лучше (безопаснее, чище(более эффективно), если вы можете
  • Вы также можете использовать мьютекс вместо семафора
  • Работа с сигналами - неприятная работа.Перед началом работы убедитесь, что вы (пере) прочитали о
    • async-signal-safety
    • потоков и сигналов
    • прерывания и перезапуска системных вызовов (SA_RESTART)
  • Я почти уверен, sem_wait(3) не безопасен для асинхронного сигнала, но это безопасно, если вы не используете SA_NODEFER (не то чтобы у вас была какая-либо причина)

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

Редактировать

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

1 голос
/ 21 апреля 2011

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

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

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

1 голос
/ 21 апреля 2011

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

0 голосов
/ 26 апреля 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 раз быстрее, чем использование мьютексов и условных переменных.

Вот некоторый код , использующий эту технику.

...