Linux系统编程(17)——线程控制-结束线程、等待线程、线程分离

博客介绍了线程控制的相关知识,包括结束线程的三种方式,即入口函数结束、pthread_exit和pthread_cancel;等待线程的目的是防止内存泄露,使用pthread_join函数;线程分离后无需pthread_join回收,用pthread_detach函数。还给出多线程应用场景及线程数量与效率的关系。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

结束线程

1.让线程的入口函数结束执行------最常见最主要使用的结束方式

2.pthread_exit:让本线程结束------但是很少使用它,它的参数 void* 表示线程结束的返回结果(很少用到);如果exit  全部线程都没了,这个不能混淆了。exit 结束进程。

void* ThreadEntry(void* arg) {  //新线程入口,参数
	(void)arg;
	while (1) {
		printf("In ThreadEntry, %lu\n", pthread_self()); 
                 //pthread_self() 获取自己的线程的ID
		Sleep(1);
	}
	pthread_exit(NULL);
}

3.pthread_cancel:让任意一个线程结束。(前提:本进程中的线程

        pthread_cancel(tid);
        //tid:对应线程的ID,结束该ID对应的线程

事务:要求具有“原子性”,要么不做,要么做完,不能做一半,半途而,可能会导致数据被破坏。这样的后果非常严重


等待线程:

目的和进程等待类似,防止出现类似僵尸进程的内存泄露情况。有回收资源的功能。

函数:

pthread_join(pthread_t thread,void **retval)   最重要的功能是等待。

参数:

pthread_t thread:等待指定ID<thread>线程

void **retval:输出型参数,可以无视他。NULL 就好了

        pthread_join(tid, NULL);
        //等待线程ID为<tid>  的线程,结束之后在执行

新线程就一直执行,主线程就一直阻塞在新线程上。要查看阻塞到哪:pstask  tid   (这个非常非常重要,tid:进程ID)


线程分离(类似 忽略SIGCHLD 信号,即不需要知道结果)

线程分离之后,不需要pthread_join回收了。

函数:

pthread_detach(pthread_t thread)

参数:

pthread_t thread:线程ID

	pthread_detach(tid);
	while (1)
	{
		printf("In Main Thread", pthread_self());  
                //pthread_self() 获取自己的线程的ID
	}
        //分离之后,主线程就继续无限循环打印,哪个新线程就分离了。

一个多线程的小场景: 

例如,计算一个很大的矩阵相乘,可以使用多线程的方式来计算,每个线程计算其中的一部分结果,最终等所有的线程都执行完毕,有主线程来汇总最终的结果,主线程就需要pthread_join 来保证所有的线程都算完了,主线程才继续执行。

 例子:多线程利用多核资源

void* ThreadEntry(void* arg) {  //新线程入口,参数
	(void)arg;
	while (1);
	return NULL;
}


int main() {

	pthread_t tid1,tid2;
	pthread_create(&tid1, NULL, ThreadEntry, &arg);
        pthread_create(&tid2, NULL, ThreadEntry, &arg);
        ……
	//主线程
	while (1)
	return 0;
}

结果:用top命令 看 CPU占有率,这时候会是百分之二百,线程数量的增多,CPU占有率就会上升最多提高到你的内核数量线程部署越多越好,到达一定程度,上限之后,线程数继续增多,反而会降低效率,线程多了,CPU调度就越多,

问:那多少线程又合适呢?

不能回答到底有多少数字,要看执行的是什么任务:CPU密集/IO密集,其中IO操作是不占CPU的。

线程的数目喝工作的类型有关,究竟多少合适,要通过测试来判定。


例子:线程之间能够共享虚拟地址


//线程控制相关函数
//创建进程
//参数:
//pthread_t *thread:线程ID的地址
//const pthread_attr_t *att:是个结构体,设置属性,一般用不到,NULL就好了 
//void *(*strart_routine)(void*):函数指针,就相当于新线程的入口函数,指定了新线程执行那个代码
//void *arg:上个函数指针,入口函数的参数就是这个。


//创建线程
#include <stdio.h>
#include<pthread.h> //头文件
#include <unistd.h>  //sleep头文件


int g_count = 0;  //栈上的变量

void* ThreadEntry(void* arg) {  //新线程入口,参数
	(void)arg;
	while (1) {
		printf("In ThreadEntry\n");  
		++g_count;
		Sleep(1);
	}
	return NULL;
}


int main() {
        //new,malloc就在堆上创建

	pthread_t tid;
	pthread_create(&tid, NULL, ThreadEntry, &arg);
	//主线程
	pthread_detach(tid);  //线程分离
	while (1)
	{
		printf("In Main Thread %d\n", g_count);  
	}
	return 0;
}

//结果在不断+1  可见供用一个虚拟地址空间

//Makefile文件中
teat:teat.c
	gcc $^ -o $@ - lpthread

结果就会不断 +1,就可以看出来:共用一个虚拟地址空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值