线程分离属性、线程互斥、死锁、信号量——进程与线程——day11

本文详细介绍了线程分离属性的使用、线程互斥锁和信号量在避免资源竞争和同步代码中的作用,以及如何通过死锁条件和避免策略来管理多线程并发。实例演示了C语言中pthread和信号量的实践应用。
摘要由CSDN通过智能技术生成

今天主要学习了线程分离属性、线程互斥、死锁、信号量

线程分离属性:主要是让线程结束后,自动回收线程空间

pthread_attr_init
    int pthread_attr_init(pthread_attr_t *attr);
    功能:
      	线程属性初始化

pthread_attr_destroy
	int pthread_attr_destroy(pthread_attr_t *attr);
	功能:
 	 	 线程属性销毁

pthread_attr_setdetachstate 
	int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
	功能:
  		设置分离属性 
  		PTHREAD_CREATE_DETACHED   分离属性
  		PTHREAD_CREATE_JOINABLE   加入属性(默认)

练习:练习:定义一个学生结构体
struct student
{
char name[32];
char sex;
int age;
int score;
};
创建两个线程,线程1负责从终端接收学生信息,线程2负责将学生信息打印在终端

#include"head.h"	//头文件

struct student{			//学生结构体
	char name[20];
	char sex;
	int age;
	int score;
};

void *thread1(void *arg)	//线程1:接收信息
{	
	struct student *stu = arg;

	fgets(stu->name,sizeof(stu->name),stdin);
	stu->sex = getchar();
	scanf("%d",&stu->age);
	scanf("%d",&stu->score);

	return NULL;
}

void *thread2(void *arg)	//输出
{
	sleep(10);
	struct student *stu = arg;

	printf("name:%s",stu->name);
	printf("sex:%c\n",stu->sex);
	printf("age:%d\n",stu->age);
	printf("score:%d\n",stu->score);

	return NULL;
}

int main(void)
{
	pthread_t tid1;		//线程1ID
	pthread_t tid2;		//线程2ID
	struct student s; 

	pthread_create(&tid1,NULL,thread1,&s);	//创建线程1
	pthread_create(&tid2,NULL,thread2,&s);	//创建线程2
	
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	
	return 0;
}

结果:
在这里插入图片描述

线程互斥

1.互斥锁:防止资源竞争

2.函数接口:

pthread_mutex_init:
      int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);
      功能:
        互斥锁初始化
      参数:
        mutex:互斥锁空间首地址
        attr:互斥锁的属性(默认为NULL)
      返回值:
        成功返回0 
        失败返回错误码 

pthread_mutex_destroy:
      int pthread_mutex_destroy(pthread_mutex_t *mutex);
      功能:
        互斥锁销毁
      参数:
        mutex:互斥锁空间首地址
      返回值:
        成功返回0 
        失败返回错误码 

pthread_mutex_lock:
      int pthread_mutex_lock(pthread_mutex_t *mutex);
      功能:
        上锁

pthread_mutex_unlock:
      int pthread_mutex_unlock(pthread_mutex_t *mutex);
      功能: 
        解锁

eg:

#include"head.h"

int val = 0;
int num1 = 0;
int num2 = 0;
pthread_mutex_t lock;	//创建互斥锁

void *thread1(void *arg)	//线程1:两个数自增
{
	while(1)
	{
		pthread_mutex_lock(&lock);	//上锁
		num1 = val;
		num2 = val;
		pthread_mutex_unlock(&lock);	//解锁
		val++;
	}

	return NULL;
}

void *thread2(void *arg)	//线程2:输出全局变量num1,num2
{
	while(1)
	{
		pthread_mutex_lock(&lock);
		if(num1 != num2)
		{
			printf("num1 = %d,num2 = %d\n",num1,num2);
		}
		pthread_mutex_unlock(&lock);
	}
	return NULL;
}

int main(void)
{
	pthread_t tid1;
	pthread_t tid2;
	pthread_mutex_init(&lock,NULL);	//互斥锁初始化

	pthread_create(&tid1,NULL,thread1,NULL);	//创建线程1
	pthread_create(&tid2,NULL,thread2,NULL);	//创建线程2

	pthread_join(tid1,NULL);	//回收线程空间,具有阻塞功能
	pthread_join(tid2,NULL);

	pthread_mutex_destroy(&lock);	//互斥锁销毁

	return 0;
}

结果:
在这里插入图片描述
因为线程与进程一样,宏观并行,微观串行,当无互斥锁时,当线程1进行到给num2赋值时,线程2进行比较并输入,则回输出出来,所以该练习可以体现互斥锁的重要性。

3.临界资源、临界区:

	加锁解锁中间的代码称为临界资源、临界区
    同一时刻临界资源不能同时执行,只能执行其中一个临界资源代码

原子操作:

    CPU最小的一次不能被任务调度打断的操作称为原子操作

互斥锁只能解决资源竞争的问题,无法同步代码(没有先后执行的顺序关系)

死锁

多线程操作互斥锁,导致多个线程均无法向下执行的状态称为死锁状态简称为死锁

	死锁产生的四个必要条件:
 		1.互斥条件
  		2.不可剥夺条件
	  	3.请求保持
  		4.循环等待

	避免产生死锁:
 		1.pthread_mutex_trylock 替代 pthread_mutex_lock
	    2.加锁顺序保持一致

信号量

信号量是一种资源,可以被初始化、申请、释放、销毁
	P操作:申请资源
	V操作:释放资源
sem_init  
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    功能:
      初始化信号量
    参数:
      sem:信号量空间首地址
      pshared:
        0 一个进程中的所有线程间共享
        非0 进程间共享 
      value:
        初始化的值
    返回值:
      成功返回0 
      失败返回-1 
    
    sem_destroy:
    int sem_destroy(sem_t *sem);
    功能:
      信号量的销毁
    参数:
      sem:信号量空间首地址
    返回值:
      成功返回0 
      失败返回-1 

    sem_wait:
    int sem_wait(sem_t *sem);
    功能:
      申请信号量

    sem_post:
    int sem_post(sem_t *sem);
    功能:
      释放信号量

eg:线程1获取字符串,线程2输出

#include"head.h"

char tmpbuff[4096] = {0};
sem_t sem_w;	//定义全局变量信号量
sem_t sem_r;

void *pthread1(void *arg)	//线程1:获取字符串
{
	while(1)
	{	
		sem_wait(&sem_w);	//申请w信号量,信号量-1
		gets(tmpbuff);
		sem_post(&sem_r);	//释放r信号量,信号量+1
	}
	return NULL;
}

void *pthread2(void *arg)	//线程2:输出字符串
{
	while(1)
	{	
		sem_wait(&sem_r);	//申请r信号量,信号量-1
		printf("tmpbuff = %s\n",tmpbuff);
		sem_post(&sem_w);	//释放w信号量,信号量+1
	}
	return NULL;
}

int main(void)
{
	pthread_t tid1;	//线程1ID
	pthread_t tid2;	//线程2ID

	sem_init(&sem_w,0,1);	//w信号量初始化,参数2中0代表一个进程中的所有线程间共享
	//参数3中1代表:初始化的值为1,因为要先进行线程1,需要申请w信号量
	sem_init(&sem_r,0,0);

	pthread_create(&tid1,NULL,pthread1,NULL);	//创建线程1
	pthread_create(&tid2,NULL,pthread2,NULL);	//创建线程2

	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);

	sem_destroy(&sem_w);	//信号量w销毁
	sem_destroy(&sem_r);	//信号量r销毁

	return 0;
}

以上就是今天的全部内容!努力努力!

  • 12
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值