Ответ 1
Как отметил @sarnold, по умолчанию ваш поток не может быть отменен с помощью pthread_cancel()
без вызова каких-либо функций, которые являются точками отмены... но это можно изменить, используя pthread_setcanceltype()
, чтобы установить тип отмены потока для асинхронный, а не отложенный. Чтобы сделать это, вы должны добавить что-то вроде pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS,NULL);
рядом с началом вашей функции потока, прежде чем вы начнете цикл. Затем вы сможете завершить поток, вызвав pthread_cancel(th)
из main()
.
Обратите внимание, однако, что это отмена потоков таким образом (независимо от того, асинхронна или нет) не очищает ресурсы, выделенные в функции потока (как заметил Кевин в комментарии). Чтобы сделать это чисто, вы можете:
- Убедитесь, что нить не делает ничего, что необходимо для очистки перед выходом (например, используя
malloc()
для выделения буфера) - Убедитесь, что у вас есть способ очистки после потока в другом месте, после выхода потока
- Используйте
pthread_cleanup_push()
иpthread_cleanup_pop()
для добавления обработчиков очистки для очистки ресурсов при отключении потока. Обратите внимание, что это все еще опасно, если тип отмены является асинхронным, потому что поток может быть отменен между распределением ресурса и добавлением обработчика очистки. - Избегайте использования
pthread_cancel()
и попробуйте проверить какое-либо условие, чтобы определить, когда прекратить (что будет проверено в длинных циклах). Поскольку ваш поток затем проверяет само завершение, он может выполнить любую очистку, необходимую ему после проверки.
Один из способов реализации последней опции - использовать мьютекс в качестве флага и протестировать его с помощью pthread_mutex_trylock()
, завернутого в функцию, используемую в тестах цикла:
#include <pthread.h>
#include <unistd.h>
#include <errno.h>
/* Returns 1 (true) if the mutex is unlocked, which is the
* thread signal to terminate.
*/
int needQuit(pthread_mutex_t *mtx)
{
switch(pthread_mutex_trylock(mtx)) {
case 0: /* if we got the lock, unlock and return 1 (true) */
pthread_mutex_unlock(mtx);
return 1;
case EBUSY: /* return 0 (false) if the mutex was locked */
return 0;
}
return 1;
}
/* Thread function, containing a loop that infinite except that it checks for
* termination with needQuit()
*/
void *thread_do(void *arg)
{
pthread_mutex_t *mx = arg;
while( !needQuit(mx) ) {}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t th;
pthread_mutex_t mxq; /* mutex used as quit flag */
/* init and lock the mutex before creating the thread. As long as the
mutex stays locked, the thread should keep running. A pointer to the
mutex is passed as the argument to the thread function. */
pthread_mutex_init(&mxq,NULL);
pthread_mutex_lock(&mxq);
pthread_create(&th,NULL,thread_do,&mxq);
sleep(2);
/* unlock mxq to tell the thread to terminate, then join the thread */
pthread_mutex_unlock(&mxq);
pthread_join(th,NULL);
sleep(2);
return 0;
}
Если поток не отсоединен (как правило, это не по умолчанию), вы должны вызвать pthread_join()
после остановки потока. Если поток отсоединен, вам не нужно присоединяться к нему, но вы не будете точно знать, когда он закончится (или даже приблизительный, если вы не добавите другой способ указать его выход).