Как указал @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's 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's 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()
после остановки потока.Если поток отсоединен, вам не нужно присоединяться к нему, но вы не будете точно знать, когда он закончится (или даже приблизительно, если вы не добавите другой способ указать его выход).