如何在 C 程序中终止线程

举报
Tiamo_T 发表于 2022/06/14 17:23:18 2022/06/14
【摘要】 在Linux线程系列的第二部分(线程创建和识别)中,我们讨论了线程ID,如何比较两个线程ID以及如何创建线程。在本文中,我们将主要关注线程是如何终止的。C 线程示例程序如果我们采用本系列第二部分中讨论的相同示例:#include<stdio.h>#include<string.h>#include<pthread.h>#include<stdlib.h>#include<unistd.h>p...

在Linux线程系列的第二部分(线程创建和识别)中,我们讨论了线程ID,如何比较两个线程ID以及如何创建线程。

在本文中,我们将主要关注线程是如何终止的。

C 线程示例程序

如果我们采用本系列第二部分中讨论的相同示例:

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    pthread_t id = pthread_self();

    if(pthread_equal(id,tid[0]))
    {
        printf("\n First thread processing\n");
    }
    else
    {
        printf("\n Second thread processing\n");
    }

    for(i=0; i<(0xFFFFFFFF);i++);

    return NULL;
}

int main(void)
{
    int i = 0;
    int err;

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
            printf("\n Thread created successfully\n");

        i++;
    }

    sleep(5);
    return 0;
}

您是否观察到正在使用的“sleep()”函数?您是否有关于为什么使用 sleep() 的问题?好吧,如果你这样做了,那么你就在正确的地方得到答案,如果你没有,那么它也将是一个很好的预读。

如果我从上面的代码中删除 sleep() 函数,然后尝试编译并运行它,我会看到以下输出:

$ ./threads
Thread created successfully
First thread processing
Thread created successfully

但是,如果我在启用 sleep() 的情况下运行它,那么我会看到输出为:

$ ./threads
Thread created successfully
First thread processing
Thread created successfully
Second thread processing

因此,如果我们删除 sleep() 函数,我们会看到日志“第二线程处理”丢失。


那么,为什么会发生这种情况?嗯,这是因为就在第二个线程即将被调度之前,父线程(从它创建了两个线程)完成了它的执行。这意味着运行 main() 函数的默认线程已完成,因此进程在 main() 返回时终止。

线程终止

正如上面已经讨论过的,每个程序都从至少一个线程开始,该线程是执行 main() 函数的线程。所以程序中执行的每个线程的最大生命周期就是主线程的生命周期。因此,如果我们希望主线程应该等到所有其他线程都完成,那么就有一个函数 pthread_join()。

#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);

上面的函数确保其父线程在完成之前不会终止。该函数在父线程中调用,第一个参数是要等待的线程的线程 ID,第二个参数是我们希望父线程等待的线程的返回值。如果我们对返回值不感兴趣,那么我们可以将此指针设置为 NULL。

如果我们在更广泛的层面上进行分类,那么我们会看到线程可以通过三种方式终止:

  1. 如果线程从其启动例程返回。
  2. 如果它被其他线程取消。这里使用的函数是 pthread_cancel()。
  3. 如果它从自身内部调用 pthread_exit() 函数。

这里的重点是 pthread_exit()。它的原型如下:

#include <pthread.h>
void pthread_exit(void *rval_ptr);

所以我们看到这个函数只接受一个参数,就是调用这个函数的线程的返回值。该返回值由等待该线程终止的父线程访问。由 pthread_exit() 函数终止的线程的返回值可以在上面刚刚解释的 pthread_join 的第二个参数中访问。

C 线程终止示例

让我们举个例子,我们使用上面讨论的函数:

#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>

pthread_t tid[2];
int ret1,ret2;

void* doSomeThing(void *arg)
{
    unsigned long i = 0;
    pthread_t id = pthread_self();

    for(i=0; i<(0xFFFFFFFF);i++);

    if(pthread_equal(id,tid[0]))
    {
        printf("\n First thread processing done\n");
        ret1  = 100;
        pthread_exit(&ret1);
    }
    else
    {
        printf("\n Second thread processing done\n");
        ret2  = 200;
        pthread_exit(&ret2);
    }

    return NULL;
}

int main(void)
{
    int i = 0;  
    int err;
    int *ptr[2];

    while(i < 2)
    {
        err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
        if (err != 0)
            printf("\ncan't create thread :[%s]", strerror(err));
        else
            printf("\n Thread created successfully\n");

        i++;
    }

    pthread_join(tid[0], (void**)&(ptr[0]));
    pthread_join(tid[1], (void**)&(ptr[1]));

    printf("\n return value from first thread is [%d]\n", *ptr[0]);
    printf("\n return value from second thread is [%d]\n", *ptr[1]);

    return 0;
}

在上面的代码中:

  • 我们使用 pthread_create() 创建了两个线程
  • 两个线程的启动函数相同,即 doSomeThing()
  • 线程使用带有返回值的 pthread_exit() 函数从 start 函数中退出。
  • 在线程创建后的main函数中,调用pthread_join()函数等待两个线程完成。
  • 一旦两个线程都完成,它们的返回值将由 pthread_join() 调用中的第二个参数访问。

上述代码的输出如下:

$ ./threads
Thread created successfully
Thread created successfully
First thread processing done
Second thread processing done
return value from first thread is [100]
return value from second thread is [200]

所以我们看到两个线程都完全执行,并且在主函数中访问了它们的返回值。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。