系统编程06-(pthread_attr_init、pthread_attr_setdetachstate、pthread_attr_destroy、pthread_detach......)

本文详细介绍了Linux系统编程中线程的属性,特别是分离属性的创建与效果,通过pthread函数进行线程的创建、取消和同步互斥操作。重点讲解了pthread_attr_setdetachstate、pthread_detach、pthread_cancel等函数的使用,以及有名和无名信号量在多线程同步中的应用。通过多个练习,探讨了线程同步互斥的重要性和实现方法。

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

目录

一、线程的属性----分离属性(attr->attribute)

1.什么是分离属性?

2.如何创建分离属性的线程? -> pthread_attr_setdetachstate()  -> man 3

方法一:添加一个分离属性到一个属性变量中,然后使用属性变量去创建一个线程,那么创建出来的线程就是具有分离属性的线程。

练习1: 验证一个分离属性的线程退出,主线程还可不可以去接合(阻塞等待回收)它?  --不可以

练习3:    使用pthread_detach之后来验证pthread_join阻塞失败?(注意分离属性时间生效的问题)

练习4:验证设置了分离属性的线程,在进程中最多能创建多少条???  --没有限制

二、线程的取消(杀死一个子线程)

1.一般主线程不用于去处理任务,只是控制子线程状态,例如取消,接合..   -> pthread_cancel() -> man 3 pthread_cancel

2.设置线程响应取消的状态。  -> pthread_setcancelstate()  -> man 3 pthread_setcancelstate

3.设置线程响应取消的类型。  -> pthread_setcanceltype()  -> man 3 pthread_setcanceltype

三、线程取消例程函数

1.什么是线程取消例程函数

2.为什么要使用取消例程函数

3.如何实现

1)压栈线程的取消例程函数-> pthread_cleanup_push()

2)弹栈线程的取消例程函数  --> pthread_cleanup_pop()

练习5:  子线程收到主线程给自己发送的取消请求,不要马上取消,而是先打印一句话"I recv cancel!\n",再响应取消。顺便使用这个练习,验证以上这3种情况。

四、多条线程同时访问某一片内存空间导致数据践踏

五、线程同步互斥方式

1、什么是同步互斥?为什么要处理同步互斥?

2、处理同步互斥方式有哪些?

六、同步互斥方式 -- 有名信号量

1.有名信号量的特点

2.有名信号量的函数接口

1)创建并打开一个有名信号量  -> sem_open()

2)有名信号量的P操作

3)有名信号量的V操作

4)关闭有名信号量。   -> sem_close()  -> man 3 sem_close

3.有名信号量与信号量的比较

七、同步互斥方式  --- 无名信号量

1.什么是无名信号量?

2.无名信号量 函数接口

1)定义一个无名信号量  (数据类型: sem_t)

2)初始化无名信号量。 -> sem_init()  -> man 3 sem_init

3)无名信号量的P操作

4)无名信号量的V操作

5)销毁无名信号量。 -> sem_destroy()  -> man 3 sem_destroy

练习6: 有一个进程,创建5个线程出来,每一个线程任务都是一样。任务: 将"helloworld"字符串每隔1S打印一个字符。   -> 任务:10S结果: hhhhheeeeellllllllllooooowwwwwooooorrrrrlllllddddd    1S   1S   1S  1S    1S   1S  1S   1S    1S  1S

练习7: 有一个进程,创建5个线程出来,每一个线程任务都是一样。  (使用无名信号量去处理同步互斥)  -> 0是不能变成-1的任务: 将"helloworld"字符串每隔1S打印一个字符。   -> 任务:10S结果: helloworldhelloworldhelloworldhelloworldhelloworld10S       10S      10S        10S       10S


一、线程的属性----分离属性(attr->attribute)

1.什么是分离属性?

首先分离属性是线程的一个属性,有了分离属性的线程,不需要别的线程去接合自己的(回收自己的资源)。但是虽然说是分离的,但是进程退出了,该线程还是会退出的。

设置了分离属性的线程  -> 不需要pthread_join()
设置了非分离属性的线程  -> 需要pthread_join()   -> 默认创建的普通属性线程就是非分离线程。

2.如何创建分离属性的线程? -> pthread_attr_setdetachstate()  -> man 3

pthread_attr_setdetachstate


方法一:添加一个分离属性到一个属性变量中,然后使用属性变量去创建一个线程,那么创建出来的线程就是具有分离属性的线程。

1)定义一个属性变量  -> 数据类型:pthread_attr_t
pthread_attr_t attr;
2)初始化属性变量。  -> pthread_attr_init()  -> man 3 pthread_attr_init
#include <pthread.h>
int pthread_attr_init(pthread_attr_t *attr);
参数:
    attr:未初始化的属性变量
返回值:
    成功:0
    失败:非0错误码
3)设置分离属性到属性变量中。
#include <pthread.h>
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
参数:
    attr:已经初始化过的属性变量
    detachstate:
        PTHREAD_CREATE_DETACHED  -> 分离属性
        PTHREAD_CREATE_JOINABLE  -> 非分离属性(默认状态)

返回值:
    成功:0
    失败:非0错误码
4)使用属性变量去创建一个新的线程。
pthread_create(&tid,&attr,.....);   -> 创建出来的线程就是分离属性的线程,不需要pthread_join()
5)销毁属性变量。  -> pthread_attr_destroy()  -> man 3 pthread_attr_destroy
int pthread_attr_destroy(pthread_attr_t *attr);
参数:
    attr:已经初始化过的属性变量
返回值:
    成功:0
    失败:非0错误码

#include<stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1 : 如何创建具有分离属性的线程

void* start_routine(void *arg)
{
    printf("[%lu]start_routine\n",pthread_self()); //pthread_self打印当前线程的ID号
    sleep(3);
}

int main()
{
    //1、定义一个线程属性变量
    pthread_attr_t attr;

    //2、初始化清空属性变量
    pthread_attr_init(&attr);

    //3、把分离属性加入到属性变量中
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

    //4、创建一条具有分离属性的子线程
    pthread_t thread;
    pthread_create(&thread,&attr,start_routine,NULL);

    //5、销毁属性变量
    pthread_attr_destroy(&attr);

    pause();//暂停自己
}

练习1: 验证一个分离属性的线程退出,主线程还可不可以去接合(阻塞等待回收)它?  --不可以

#include<stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1 : 如何创建具有分离属性的线程

void* start_routine(void *arg)
{
	int cnt = 10;
	while(cnt--)
	{	
		printf("[%s] is job.... [%d]\n",__FUNCTION__,cnt); //pthread_self打印当前线程的ID号
		sleep(1);
	}
}

int main()
{
	//1、定义一个线程属性变量
	pthread_attr_t attr; //不要写成pthread_attr_t *attr;

	//2、初始化清空属性变量
	pthread_attr_init(&attr);

	//3、把分离属性加入到属性变量中
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
	//pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);//线程的默认状态非分离属性
	
	//4、创建一条具有分离属性的子线程
	int ret;
	pthread_t tid;
	ret = pthread_create(&tid,&attr,start_routine,NULL);
	if(ret != 0)
	{
		perror("pthread_create fail");
		return -1;
	}
	
	int cnt = 0;
	while(cnt--)
	{	
		printf("[%s] is job....\n",__FUNCTION__); //pthread_self打印当前线程的ID号
		sleep(1);
	}
	
	ret = pthread_join(tid,NULL);
	if(ret != 0)
	{
		perror("pthread_join fail");
		return -1;
	}
	
	//5、销毁属性变量
	pthread_attr_destroy(&attr);
	
	printf("main is over\n");
	
	return 0;
}

/*
int *x,*y;
get xy(int *x,int *y)
{
	*x = 10;
	*y = 20;
}
get_xy(x,y);//x,y值没有改变

int x,y;
get_xy(int *x,int *y); 
{
	*x = 10;
	*y = 20;
}
get_xy(&x,&y);//x,y值有改变
*/

练习2: 验证一个分离属性的线程,在进程退出时,该分离属性的线程还会不会继续运行?  --不会运行了

#include<stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1 : 如何创建具有分离属性的线程

void* start_routine(void *arg)
{
	int cnt = 10;
	while(cnt--)
	{	
		printf("[%s] is job.... [%d]\n",__FUNCTION__,cnt); //pthread_self打印当前线程的ID号
		sleep(1);
	}
}

int main()
{
	//1、定义一个线程属性变量
	pthread_attr_t attr; //不要写成pthread_attr_t *attr;

	//2、初始化清空属性变量
	pthread_attr_init(&attr);

	//3、把分离属性加入到属性变量中
	pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
	//pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_JOINABLE);//线程的默认状态非分离属性
	
	//4、创建一条具有分离属性的子线程
	int ret;
	pthread_t tid;
	ret = pthread_create(&tid,&attr,start_routine,NULL);
	if(ret != 0)
	{
		perror("pthread_create fail");
		return -1;
	}
	
	int cnt = 5;
	while(cnt--)
	{	
		printf("[%s] is job....[%d]\n",__FUNCTION__,cnt); //pthread_self打印当前线程的ID号
		sleep(1);
	}
	
	//添加了分离属性的子线程,主线程不需要调用pthread_join去结合它
	
	//5、销毁属性变量
	pthread_attr_destroy(&attr);
	
	printf("main is over\n");
	
	return 0;
}

/*
int *x,*y;
get xy(int *x,int *y)
{
	*x = 10;
	*y = 20;
}
get_xy(x,y);//x,y值没有改变

int x,y;
get_xy(int *x,int *y); 
{
	*x = 10;
	*y = 20;
}
get_xy(&x,&y);//x,y值有改变
*/

#include<stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
//方法1 : 如何创建具有分离属性的线程

/*
练习1: 验证一个分离属性的线程退出,主线程还可不可以去接合(阻塞等待回收)它?
练习2: 验证一个分离属性的线程,在进程退出时,该分离属性的线程还会不会继续运行?
*/

void* start_routine(void *arg)
{
    printf("[%lu]start_routine\n",pthread_self()); //pthread_self打印当前线程的ID号
    sleep(3);
}

int main()
{
    //1、定义一个 线程属性变量
    pthread_attr_t attr;

    //2、初始化清空 属性变量
    pthread_attr_init(&attr);

    //3、把分离属性 加入 到 属性变量中
    pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);

    //4、创建一条具有分离属性的子线程
    pthread_t thread;
    pthread_create(&thread,&attr,start_routine,NULL);

    //5、销毁属性变量
    pthread_attr_destroy(&attr);

    //阻塞等待子线程退出,回收资源
    int ret = pthread_join(thread,NULL);
    if(ret != 0){
        printf("pthread_join error\n");
    }
}
现象:
    pthread_join失败,回收资源失败

方法二:先创建一个普通线程,然后在线程中调用一个设置分离属性的函数,那么这个线程就变成分离的属性。
1)设置线程本身的属性为分离属性。  -> pthread_detach()   -> man 3 pthread_detach
#include <pthread.h>
int pthread_detach(pthread_t thread);
函数作用:
    设置分离属性给线程
参数:
    thread:需要设置分离属性的线程的ID号
返回值:
    成功:0
    失败:非0错误码
2)获取线程的ID号。 -> pthread_self()  -> man 3 pthread_self
#include <pthread.h>
pthread_t pthread_self(void);
参数:
    无
返回值:线程的ID号。
#include<stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1 : 如何创建具有分离属性的线程
void* start_routine(void *arg)
{
    //在子线程的内部 设置 分离属性
    pthread_detach(pthread_self());
    printf("[%lu]start_routine\n",pthread_self()); //pthread_self打印当前线程的ID号
}

int main()
{
    //4、创建一条具有分离属性的子线程
    pthread_t thread;
    pthread_create(&thread,NULL,start_routine,NULL);
    //pause();
}
现象:

练习3:
    使用pthread_detach之后来验证pthread_join阻塞失败?(注意分离属性时间生效的问题)

#include<stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1 : 如何创建具有分离属性的线程

void* start_routine(void *arg)
{
	pthread_detach(pthread_self()); //写法二
	
	int cnt = 10;
	while(cnt--) //子线程想要工作10秒
	{	
		printf("[%s] is job.... [%d]\n",__FUNCTION__,cnt); //pthread_self打印当前线程的ID号
		sleep(1);
	}
	
	//pthread_exit(NULL);
}

int main()
{
	int ret;
	pthread_t tid;
	ret = pthread_create(&tid,NULL,start_routine,NULL);
	if(ret != 0)
	{
		perror("pthread_create fail");
		return -1;
	}
	
	//pthread_detach(tid); //写法一
	
	int cnt = 5;
	while(cnt--) //主线程工作5秒之后是退出还是等待---退出
	{	
		printf("[%s] is job....[%d]\n",__FUNCTION__,cnt); //pthread_self打印当前线程的ID号
		sleep(1);
	}
	
	//添加了分离属性之后,pthread_join就不用了
/* 	ret = pthread_join(tid,NULL);
	if(ret != 0)
	{
		perror("pthread_join fail");
		return -1;
	} */
	
	printf("main is over\n");
	
	return 0;
}


练习4:验证设置了分离属性的线程,在进程中最多能创建多少条???  --没有限制

#include<stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#include <stdlib.h>

//方法1:如何创建具有分离属性的线程
void* start_routine(void *arg)
{
    //在子线程的内部设置分离属性
    pthread_detach(pthread_self());
    printf("[%lu]start_routine\n",pthread_self()); //pthread_self打印当前线程的ID号
}

int main()
{
    //4、创建一条具有分离属性的子线程
    pthread_t thread;
    int cnt=0;

    while(1)
    {
        int ret= pthread_create(&thread,NULL,start_routine,NULL);
        if(ret != 0){
            printf("pthread_create error\n");
            break;
        }
        printf("cnt:%d\n",cnt++);
    }
}

总结:
 无论是否添加了分离属性的线程,理论上创建的线程的数量没有限制。

二、线程的取消(杀死一个子线程)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值