如何在 C 程序中终止线程
在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。
如果我们在更广泛的层面上进行分类,那么我们会看到线程可以通过三种方式终止:
- 如果线程从其启动例程返回。
- 如果它被其他线程取消。这里使用的函数是 pthread_cancel()。
- 如果它从自身内部调用 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]
所以我们看到两个线程都完全执行,并且在主函数中访问了它们的返回值。
- 点赞
- 收藏
- 关注作者
评论(0)