关于人工智能:Linux线程-创建-终止-回收-分离

6次阅读

共计 4681 个字符,预计需要花费 12 分钟才能阅读完成。

一、线程简介

  • 线程是参加系统调度的最小单位。它被蕴含在过程之中,是过程中的理论运行单位。
  • 一个过程中能够创立多个线程,多个线程实现并发运行,每个线程执行不同的工作。
  • 每个线程都有其对应的标识,称为线程 ID,线程 ID 应用 pthread_t 数据类型来示意。

二、线程的创立

线程是轻量级的并发执行单元,通过调用 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;
}

三、线程的终止

线程的终止有两种形式:天然终止 强制终止

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

线程天然终止

线程能够通过调用 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 函数返回了一个字符串,如果子线程失常完结,那么在主线程中打印进去的将是这个字符串;如果子线程被强制终止,那么在主线程中打印进去的将是 线程被勾销!

  • 🙈不是这个啦
  • 我是想说,后面好几次都提到了 线程回收, 你是不是忘了通知我了
  • 👧 不好意思哈,一下子没忍住就说进去了

四、线程的回收

应用 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 指向的值是未定义的。

如果线程终止后,其它线程没有调用 pthread_join()函数来回收该线程,这个线程会变成僵尸线程,会节约系统资源;若僵尸线程积攒过多,那么会导致应

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

五、线程的拆散

能够应用 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 线程的创立、终止、回收、拆散等基本操作。

在理论编程中,咱们可能还须要应用一些其余的函数和技巧,例如互斥锁、条件变量、信号量、读写锁等

👧 欲知后事如何,请听下回分解!


📢欢送各位 👍点赞 ⭐珍藏 📝评论,如有谬误请留言斧正,非常感谢!

以上,如果感觉对你有帮忙,点个赞再走吧,这样 @知微之见也有更新上来的能源!

也欢送私信我,一起交换!

正文完
 0