一、线程简介

Linux线程 | 创建 终止 回收 分离

  • 线程是参加体系调度的最小单位。它被包含在进程之中,是进程中的实践运转单位。

  • 一个进程中能够创立多个线程,多个线程完成并发运转,每个线程履行不同的使命。

  • 每个线程都有其对应的标识,称为线程 ID,线程 ID 运用 pthread_t 数据类型来表明。

Linux线程 | 创建 终止 回收 分离

二、线程的创立

线程是轻量级的并发履行单元,经过调用Linux体系供给的pthread库中的函数来创立和办理线程。

  • 包含头文件:
#include <pthread.h>
  • 定义线程函数:

线程函数是线程实践履行的函数,可所以任何能够被调用的函数。线程函数的原型如下:

void* thread_function(void* arg);

其间arg是传递给线程函数的参数,可所以任何类型的数据。线程函数的回来值为void*类型,能够回来任何类型的数据。

  • 创立线程:

创立线程需求调用pthread_create函数。该函数的原型如下:

int pthread_create(pthread_t* thread, const pthread_attr_t* attr, void* (*start_routine)(void*), void* arg);
参数 类型 描绘
thread pthread_t * 用于存储新线程标识符的指针
attr const pthread_attr_t * 用于指定新线程的特点,如栈大小、调度战略等,能够为 NULL,表明运用默许特点
start_routine void *(*)(void *) 新线程的开始函数,需求回来 void 指针类型的成果,而且带有一个 void 指针类型的参数
arg void * 传递给新线程开始函数的参数,能够为 NULL
回来值 int 0 表明成功,非 0 表明失利,错误代码保存在 errno

留意:在调用 pthread_create() 函数之后,新线程的履行与调用线程并行进行,它们之间没有特定的履行顺序。

下面是一个创立线程的比如:

#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("这是线程函数,arg=%d, i=%d\n", *(int *)arg, i);
        sleep(1);
    }
    pthread_exit(NULL);
}
int main()
{
    pthread_t tid; // 线程标识符
    int arg = 123; // 传递给线程函数的参数
    // 创立新线程
    if (pthread_create(&tid, NULL, thread_func, &arg) != 0) {
        printf("线程创立失利!\n");
        return 1;
    }
    // 等待线程完毕并收回资源
    if (pthread_join(tid, NULL) != 0) {
        printf("线程收回失利!\n");
        return 1;
    }
    printf("线程完毕!\n");
    return 0;
}

Linux线程 | 创建 终止 回收 分离

三、 线程的停止

线程的停止有两种方式:天然停止强制停止

线程的天然停止是指线程履行完它的工作后主动退出,而强制停止是指在程序运转过程中,主线程或其他线程显式地停止一个正在运转的线程。

线程天然停止

线程能够经过调用pthread_exit函数来完成天然停止。pthread_exit函数的原型如下:

void pthread_exit(void *retval);

pthread_exit函数 无回来值,其间,参数retval是线程的退出状况,能够经过pthread_join函数获取。

下面是一个简略的比如,演示怎么运用pthread_exit函数停止一个线程:

#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("这是线程函数,i=%d\n", i);
        sleep(1);
    }
    pthread_exit((void *) "线程正常完毕!");
}
int main()
{
    pthread_t tid; // 线程标识符
    // 创立新线程
    if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
        printf("线程创立失利!\n");
        return 1;
    }
    // 等待线程完毕并收回资源
    void *retval;
    if (pthread_join(tid, &retval) != 0) {
        printf("线程收回失利!\n");
        return 1;
    }
    printf("%s\n", (char *)retval);
    printf("线程完毕!\n");
    return 0;
}

上面的示例程序中,咱们在线程函数中调用pthread_exit函数来停止线程,并回来一个字符串作为退出状况。

在主线程中,咱们运用pthread_join函数等待线程完毕,并经过指针retval获取线程的退出状况。

线程强制停止

在Linux中,线程的强制停止能够运用pthread_cancel函数来完成。pthread_cancel函数的原型如下:

int pthread_cancel(pthread_t thread);

其间,参数thread是要撤销的线程标识符。当pthread_cancel函数被调用时,被撤销的线程将当即退出。

参数 类型 描绘
thread pthread_t 要撤销的线程标识符
回来值 int 0 表明成功,非 0 表明失利,错误代码保存在 errno

留意:调用 pthread_cancel() 函数仅仅向指定线程发送一个撤销恳求,让指定线程尽快退出履行,而不会当即停止它的履行。

线程在接收到撤销恳求后,能够经过调用 pthread_setcancelstate() pthread_setcanceltype() 函数来指定怎么呼应恳求,这里不再展开阐明。

下面是一个简略的比如,演示怎么运用pthread_cancel函数强制停止一个线程:

#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("这是线程函数,i=%d\n", i);
        sleep(1);
    }
    pthread_exit((void *) "线程正常完毕!");
}
int main()
{
    pthread_t tid; // 线程标识符
    // 创立新线程
    if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
        printf("线程创立失利!\n");
        return 1;
    }
    // 等待一段时间后强制停止线程
    sleep(2);
    if (pthread_cancel(tid) != 0) {
        printf("线程撤销失利!\n");
        return 1;
    }
    // 等待线程完毕并收回资源
    void *retval;
    if (pthread_join(tid, &retval) != 0) {
        printf("线程收回失利!\n");
        return 1;
    }
    if (retval == PTHREAD_CANCELED) {
        printf("线程被撤销!\n");
    } else {
        printf("%s\n", (char *)retval);
    }
    printf("线程完毕!\n");
    return 0;
}

上面的示例程序中,主线程调用了pthread_cancel函数,强制停止了子线程。

在子线程函数中,咱们运用pthread_exit函数回来了一个字符串,假如子线程正常完毕,那么在主线程中打印出来的将是这个字符串;假如子线程被强制停止,那么在主线程中打印出来的将是线程被撤销!

Linux线程 | 创建 终止 回收 分离

  • 不是这个啦
  • 我是想说,前面好几次都提到了线程收回, 你是不是忘了告知我了
  • 不好意思哈,一会儿没忍住就说出来了

四、线程的收回

运用pthread_join函数等待线程完毕。该函数需求两个参数:线程标识符和指向线程回来值的指针。

int pthread_join(pthread_t thread, void **value_ptr);
参数 类型 描绘
thread pthread_t 要等待的线程标识符
value_ptr void ** 用于获取线程的退出状况的指针,能够为 NULL,表明不关心退出状况
回来值 int 0 表明成功,非 0 表明失利,错误代码保存在 errno

留意:调用 pthread_join() 函数会堵塞当前线程,直到指定的线程停止停止。

假如指定的线程现已停止,那么该函数会当即回来,而且不会堵塞。

另外,线程的退出状况只要在 pthread_join() 调用成功时才干被获取,否则 value_ptr 指向的值是未定义的。

Linux线程 | 创建 终止 回收 分离

假如线程停止后,其它线程没有调用 pthread_join()函数来收回该线程,这个线程会变成僵尸线程,会糟蹋体系资源;若僵尸线程积累过多,那么会导致应

用程序无法创立新的线程。

Linux线程 | 创建 终止 回收 分离

五、线程的别离

能够运用pthread_detach函数将线程别离。pthread_detach函数的原型如下:

int pthread_detach(pthread_t thread);
参数 类型 描绘
thread pthread_t 要别离的线程标识符
回来值 int 0 表明成功,非 0 表明失利,错误代码保存在 errno 中

调用 pthread_detach() 函数将使得指定线程在退出时主动释放其相关资源,而不需求其他线程调用 pthread_join() 函数来等待它的退出并收回资源。

假如指定的线程现已被别离或许现已退出,那么调用 pthread_detach() 函数将回来一个错误。

下面是一个简略的比如,演示怎么运用pthread_detach函数将线程别离:

#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
    int i;
    for (i = 0; i < 5; i++) {
        printf("这是线程函数,i=%d\n", i);
        sleep(1);
    }
    pthread_exit((void *) "线程正常完毕!");
}
int main()
{
    pthread_t tid; // 线程标识符
    // 创立新线程
    if (pthread_create(&tid, NULL, thread_func, NULL) != 0) {
        printf("线程创立失利!\n");
        return 1;
    }
    // 别离线程
    if (pthread_detach(tid) != 0) {
        printf("线程别离失利!\n");
        return 1;
    }
    printf("线程现已别离,将主动收回资源!\n");
    // 程序完毕
    return 0;
}

上面的示例程序中,咱们在创立线程之后当行将线程别离,并打印一条提示信息,告知用户线程现已别离,将在退出时主动收回资源。

当运转上面的程序时,能够看到如下输出:

线程现已别离,将主动收回资源!
这是线程函数,i=0
这是线程函数,i=1
这是线程函数,i=2
这是线程函数,i=3
这是线程函数,i=4

能够看到,程序创立了一个新线程,并当行将它别离。在子线程中,咱们打印了5个字符串,每个字符串间隔1秒。

在主线程中,咱们打印了一条提示信息,告知用户线程现已别离,将在退出时主动收回资源。最后,程序正常完毕,没有调用pthread_join函数。

小结

咱们现已介绍了Linux线程的创立、停止、收回、别离等基本操作。

在实践编程中,咱们或许还需求运用一些其他的函数和技巧,例如互斥锁、条件变量、信号量、读写锁等

Linux线程 | 创建 终止 回收 分离

欲知后事怎么,请听下回分解!


欢迎各位 点赞 ⭐收藏 谈论,如有错误请留言纠正,非常感谢!

以上,假如觉得对你有协助,点个赞再走吧,这样@知微之见也有更新下去的动力!

也欢迎私信我,一同交流!