线程的清理、控制以及线程属性的概念

本文介绍了线程清理函数的应用及线程属性的初始化、设置和获取方法,并通过实例展示了如何利用pthread_cleanup_push和pthread_cleanup_pop实现线程清理,以及如何设置线程分离属性。

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

一. 线程清理和控制函数

如同进程可以调用atexit函数安排在它退出时需要调用的函数一样,线程也可以安排在它退出时执行一些函数。这些清理函数记录在栈中,所以它们执行的顺序和注册的顺序是相反的。

#include <pthread.h>

void pthread_cleanup_push(void(*rtn)(void*), void *arg);

void pthread_cleanup_pop(int execute);

返回:成功返回0,否则返回错误编号;

参数:rtn:清理函数指针;

            arg:调用清理函数传递的参数;

            execute:值1时执行线程清理函数,值0时不执行线程清理函数;

触发线程调用清理函数的动作:

      1)调用pthread_exit;

      2)响应取消请求;

      3)用非零execute参数调用thread_cleanup_pop时;

注意:pthread_cleanup_push和pthread_cleanup_pop时成对儿出现的。

下面给出一个案例。

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

// 定义线程清理函数
void clean_fun(void *arg)
{   
    char *s = (char*)arg;
    printf("clean_func: %s\n", s);
}
 void *th_fn(void *arg)
{
    int execute = int(arg);
    pthread_cleanup_push(clean_fun , "first clean func");
    pthread_cleanup_push(clean_fun, "sencond clean func");
    printf("thread running %lx\n", pthread_self());
    pthread_cleanup_pop(execute);
    pthread_cleanup_pop(execute);

    return (void*)0;
}

int main(void)
{
    int err;
    pthread_t th1, th2;
    
    if((err = pthread_create(&th1, NULL, th_fn, (void*)1)) != 0)
        perror("pthread create error");
    pthread_join(th1, NULL);
    printf("th1(%lx) finished\n", th1);

    if((err = pthread_create(&th2, NULL, th_fn, (void*)1)) != 0)
        perror("pthread create error");
    printf("th2(%lx) finished\n", th2);

    return 0;
}

上面程序的运行结果如下:


关于线程清理函数的一些细节,请看这篇文章。点击这里


二. 线程属性的初始化、销毁、设置和获得分离属性

1. 线程属性的初始化和销毁

#include <pthread.h>

int pthread_attr_init(pthread_attr_t *attr);

int pthread_attr_destroy(pthread_attr_t *attr);

返回:成功返回0,否则返回错误编号;

线程属性结构(pthread_attr_t)


2. 设置和获得分离属性

#include <pthread.h>

int pthread_attr_getdetachstat(const pthread_attr_t *restrict attr, int *detachstate);

int pthread_attr_setdetachstat(const pthread_attr_t *attr, int detachstate);

返回:成功返回0,出错返回错误编号;

说明:1)detachstate的取值

                   PTHREAD_CREATE_JOINABLE(默认值)---------正常启动线程

                   PTHREAD_CREATE_DETACHED------------------以分离状态启动线程

            2)以默认方式启动的线程,在线程结束后不会自动释放占有的系统资源,要在主控线程中调用pthread_join()后才会释放;

            3)以分离状态启动的线程,在线程结束后会自动释放所有占用的系统资源(主线程不需用调用pthread_join函数)


下面给出一个具体的案例。

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

void out_state(pthread_attr_t *attr)
{
	int state;
	// 获取分离属性值
	if(pthread_attr_getdetachstate(attr, &state) != 0)
		perror("getdetachstate error");
	else
	{
		if(state == PTHREAD_CREATE_JOINABLE)
			printf("joinable state\n");
		else if(state == PTHREAD_CREATE_DETACHED)
			printf("detached state\n");
		else
			printf("error state\n");
	}
}

void *th_fn(void *arg)
{
	int i;
	int sum = 0;
	for(i = 1; i <= 100; ++i)
		sum += i;

	return (void*)∑
}

int main(void)
{
	int err;
	pthread_t default_th, detach_th;
	// 定义线程属性
	pthread_attr_t attr;
	// 对线程属性初始化
	pthread_attr_init(&attr);
	// 输出分离属性(默认值)
	out_state(&attr);

	// 取分离属性的默认值,以正常方式启动子线程
	if((err = pthread_create(&default_th, &attr,
						th_fn, (void*)0)) != 0)
	{
		perror("pthread create error");
	}
	int res;
	if((err = pthread_join(default_th,
							(void*)&res)) != 0)
	{
		perror("pthread join error");
	}
	else
	{
		printf("default return is %d\n", (int)res);
	}

	printf("-------------------------------\n");

	//设置分离属性为分离状态属性
	pthread_attr_setdetachstate(&attr,
					PTHREAD_CREATE_DETACHED);
	out_state(&attr);
	//以分离状态启动子线程
	if((err = pthread_create(&detach_th, &attr,
						th_fn, (void*)0)) != 0)
	{
		perror("pthread create error");
	}

	//以分离状态启动的子线程,这里就不要调用pthread_join了 
	/*
	if((err = pthread_join(detach_th, (void*)&res)) != 0)
	{
//		perror("pthread_join error");
		fprintf(stderr, "%s\n", strerror(err));

	}
	else
	{
		printf("detach rerurn is %d\n", (int)res);
	}
	*/
	
	// 销毁线程属性
	pthread_attr_destroy(&attr);

	printf("0x%lx finished\n", pthread_self());
	sleep(1);

	return 0;
}

上面的程序运行结果如下:


在该案例中,第一个线程的属性我们以默认的方式初始化,因此主线需要调用pthread_join进行等待;第二个线程我们设置线程的属性为分离状态,在该线程结束后会自动释放所占用的系统资源,因此主线程就不再需要调用pthread_join进行等待。

注:所谓的分离,通俗一点理解就是:创建子线程后,子线程与主控线程已经没有关系,子线程执行完毕后会自动去释放资源,而不需要主线程去调用pthread_join进行回收。

所以,分离属性一般在网络通讯中应用较多(服务器端),因为对于高并发的多线程访问需要使用完后自动释放资源,否则会造成网络的拥堵。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值