Thread线程学习(3) 了解Linux线程中的pthread_cancel()函数

目录

一、了解pthread_cancel()函数

二、使用pthread_cancel()函数的基础示例

三、使用pthread_cancel()函数取消线程的进阶示例

(1) 注意事项

(2) 进阶示例

四、pthread_cancel()函数的扩展内容

(1) 如何定义取消点:

(2) 使用pthread_cancel()函数需要谨慎操作,遵循以下几点:

四、总结


        在Linux系统中,线程是一种轻量级的执行单元,它允许程序在同一进程内同时执行多个任务。然而,在某些情况下,我们可能需要在程序运行过程中取消某个线程的执行。本篇文章将介绍pthread_cancel()函数,该函数用于取消一个正在执行的线程,并通过实例来说明其使用方法。

一、了解pthread_cancel()函数

        pthread_cancel()函数是Linux系统中用于取消线程执行的函数,其原型如下:

#include <pthread.h>

int pthread_cancel(pthread_t thread);

        该函数接受一个pthread_t类型的参数thread,用于指定要取消的线程。成功取消线程时,函数返回0;否则返回非0值。调用pthread_cancel()函数后,目标线程将收到一个取消请求,然后可以在合适的时机退出线程执行。

二、使用pthread_cancel()函数的基础示例

        下面通过一个示例来演示如何使用pthread_cancel()函数取消一个线程。

#include <stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

void* thread_func(void* arg)
{
    int count = 0;
     while (1) {
        printf("Thread is running, count: %d\n", count);
        count++;
        sleep(1);
    }
    // 检查取消请求
	pthread_testcancel();
	printf("Thread cancellation requested. Exiting...\n");
	pthread_exit(NULL);
    return NULL;
}
int main()
{
    pthread_t thread;
    // 创建线程
    pthread_create(&thread, NULL, thread_func, NULL);
    // 等待一段时间
    sleep(3);
    // 取消线程执行
    pthread_cancel(thread);
    // 等待线程退出
    pthread_join(thread, NULL);
    printf("Thread canceled successfully.\n");
    return 0;
}

运行结果如下:

开始运行...

Thread is running, count: 0
Thread is running, count: 1
Thread is running, count: 2
Thread is running, count: 3
Thread canceled successfully.

运行结束。

代码的主要逻辑如下:

  1. main() 函数中,我们创建了一个子线程 thread,并将其执行函数设置为 thread_func

  2. thread_func 是子线程的执行函数。在该函数中,我们使用一个循环来模拟线程的工作,每秒打印一次计数值 count。这个循环会一直执行,直到收到取消请求。

  3. 在主线程中,我们使用 sleep(3) 等待了3秒,然后调用 pthread_cancel(thread) 来发送取消请求给子线程。

  4. 接着,我们使用 pthread_join(thread, NULL) 等待子线程退出。这样,主线程会阻塞直到子线程执行完毕。

  5. 最后,主线程输出 "Thread canceled successfully." 表示线程成功被取消。

        在运行该代码时,你会看到子线程每秒打印一次计数值,而主线程在等待3秒后取消子线程的执行。子线程收到取消请求后,输出相应的消息并退出。最后,主线程输出线程取消成功的消息。

        请注意,使用 pthread_cancel() 函数来取消线程需要小心处理,确保线程在被取消之前完成必要的清理工作,以避免资源泄漏或数据不一致的问题。在这个例子中,我们在子线程中使用 pthread_testcancel() 来检查取消请求,以确保在取消点处退出线程。

三、使用pthread_cancel()函数取消线程的进阶示例

(1) 注意事项

在使用pthread_cancel()函数取消线程之前,需要注意以下几点:

1.确保线程可以被取消:线程需要以可取消的状态运行,即需要在创建线程时设置线程的取消状态为可取消,可以通过以下方式实现:

// 设置线程的取消状态为可取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

2.设置取消类型:线程的取消类型决定了线程被取消时的行为。可以通过以下方式设置取消类型:

// 设置线程的取消类型为延迟取消
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);

常见的取消类型有PTHREAD_CANCEL_DEFERRED(线程取消在下一个取消点生效)和PTHREAD_CANCEL_ASYNCHRONOUS(立即取消线程)。

3.定义取消点:取消点是指程序中的某个位置,在该位置线程可以被取消。常见的取消点包括线程阻塞在I/O操作、休眠、等待锁等地方。

一旦线程符合上述要求,我们可以使用pthread_cancel()函数来取消线程。在主线程中调用pthread_cancel()函数,并传递要取消的线程标识符作为参数即可。例如:

// 其中thread_id为要取消的线程的标识符。
pthread_cancel(thread_id);

(2) 进阶示例

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

void* thread_function(void* arg) {
    printf("子线程开始执行\n");   
    // 设置线程的取消状态为可取消
    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); 
    // 设置线程的取消类型为延迟取消
    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
    while(1) {
        printf("子线程执行中...\n");
        sleep(1);
    }   
    printf("子线程执行完毕\n");
    pthread_exit(NULL);
}

int main() {
    pthread_t thread;
    int res;  
    // 创建子线程
    res = pthread_create(&thread, NULL, thread_function, NULL);
    if (res != 0) {
        perror("线程创建失败");
        exit(EXIT_FAILURE);
    }   
    sleep(3);   
    // 取消子线程
    res = pthread_cancel(thread);
    if (res != 0) {
        perror("线程取消失败");
        exit(EXIT_FAILURE);
    }  
    // 等待子线程结束
    res = pthread_join(thread, NULL);
    if (res != 0) {
        perror("线程等待失败");
        exit(EXIT_FAILURE);
    }  
    printf("主线程执行完毕\n");  
    return 0;
}

运行结果如下:

开始运行...

子线程开始执行
子线程执行中...
子线程执行中...
子线程执行中...
子线程执行中...
主线程执行完毕

运行结束。

        在该示例代码中,我们创建了一个子线程,并在子线程中循环打印信息。主线程等待3秒后,通过调用pthread_cancel()函数来取消子线程的执行。子线程在每次循环中都会检查是否收到取消请求,由于我们将取消类型设置为延迟取消,所以子线程会在下一个取消点处取消。

        注意,在子线程中,我们使用pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)将线程的取消状态设置为可取消,以及使用pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL)将线程的取消类型设置为延迟取消。

        运行以上代码,你将会看到子线程开始执行并不断打印信息,而在主线程中调用pthread_cancel()函数后,子线程会在下一个取消点处被取消,并输出"子线程执行完毕"。最后,主线程输出"主线程执行完毕",程序正常结束。

        请注意,实际的取消点取决于代码的具体情况,例如在阻塞I/O操作或调用特定函数时可能会有取消点。在实际的应用中,请确保你的代码中存在适当的取消点,以便能够及时响应取消请求。

四、pthread_cancel()函数的扩展内容

(1) 如何定义取消点:

取消点是指程序中的某个位置,在该位置线程可以被取消。为了定义取消点,我们可以使用以下方法:

  1. 阻塞式I/O操作:在进行阻塞式I/O操作时,线程会等待I/O完成,此时可以将这个等待过程作为取消点。例如,使用read()、write()或者select()等函数进行文件读写或网络通信时,这些函数在等待I/O完成时可以作为取消点。

  2. 线程休眠:线程调用休眠函数(如sleep()、usleep())时,线程会进入休眠状态,这个休眠过程可以作为取消点。

  3. 等待互斥锁:当线程在等待一个互斥锁时,可以将等待互斥锁的过程设置为取消点。在等待期间,线程会暂时挂起,等待其他线程释放互斥锁。

  4. 等待条件变量:当线程在等待条件变量满足条件时,可以将等待条件变量的过程设置为取消点。线程在等待期间会暂时挂起,等待其他线程发送信号满足条件。

  5. pthread_testcancel()函数:该函数是一个特殊的取消点定义方式,可以手动在代码中插入pthread_testcancel()函数,用于检测取消请求。如果有取消请求存在,该函数会立即取消线程。

在使用取消点时,需要注意以下几点:

  • 取消点的设置应该合理,以保证线程的安全性和数据一致性。取消点的位置应该在合适的地方,避免在关键代码段或者临界区内设置取消点。

  • 取消点的位置应该满足业务逻辑的要求,避免在一个关键操作前或后设置取消点,以免导致数据不一致或者程序逻辑错误。

  • 在设计多线程程序时,应该充分考虑取消点的位置和取消操作,保证程序的正确性和可维护性。

通过合理设置取消点,我们可以在需要的时候取消线程,实现更加灵活和可控的多线程编程。

(2) 使用pthread_cancel()函数需要谨慎操作,遵循以下几点:

使用pthread_cancel()函数需要谨慎操作,遵循以下几点:

  1. 在设计线程时,应该考虑线程的取消情况,并合理设置取消点,以保证线程的安全性和数据一致性。

  2. 取消一个线程时,应该确保线程在被取消前已经完成了必要的清理工作,例如释放动态分配的内存、关闭打开的文件等。

  3. 注意处理线程取消的返回值。如果pthread_cancel()函数返回0,表示成功发送取消请求,但并不代表线程立即终止。可以使用pthread_join()函数等待线程终止,并获取线程的返回值。

四、总结

         本文深入介绍了Linux线程的pthread_cancel()函数,该函数可以用于取消一个正在执行的线程。在使用pthread_cancel()函数时,需要合理设置线程的取消状态和取消类型,并确保线程在取消前完成必要的清理工作。同时,对于取消操作的返回值需要进行适当处理。合理使用pthread_cancel()函数可以帮助我们实现更加灵活和可控的多线程编程。

 笔记分享,如有误感谢指教;

猜你喜欢

转载自blog.csdn.net/qq_50635297/article/details/130719162