2021.4.09学习笔记

线程等待的目的

保证线程的退出顺序:保证一个线程退出并且回收资源后允许下一个进程退出
回收线程退出时的资源情况:保证当前线程推出后,创建的新线程不会复用刚才退出线程的地址空间
获得新线程退出时的结果是否时正确退出返回值

线程的状态

可结合态

这种状态下的线程是能被其他进程回收资源或被杀死的

可分离态

不能被其他进程回收资源或被杀死的,它存储的资源在它终止时由系统自动回收

默认情况下,线程是可结合态

线程分离函数

pthread_detach()
int pthread_detach(pthread_t thread);

功能

如果次线程不希望别人调用pthread_join 函数来回收,而是希望自己在运行结束时,自动回收资源调用pthread_detach
将pthread_detach()中的线程变为分离态

返回值

成功返回0;错误返回非零值

参数

thread:你要分离的那个次线程的TID

tach_struct:进程所有信息放在这里(进程号PID,地址空间,调度优先级)

线程切换的开销低:因为实质就是函数的切换

进程与线程的区别

1.进程是资源分配的最小单位,线程是资源调度的最小单位
2.每个进程有独立的地址空间,多个线程共享进程的地址空间,线程间的切换比进程间的切换开销小
3.线程的调度必须通过频繁的加锁来保持线程的同步,影响线程的并发性能
4.进程比线程更加健康,多进程之间相互独立,一个进程的异常对其他进程无影响,而一个线程的崩溃可能影响其他线程或整个程序
5.线程之间的通信方便(小数据量的),同一进程下,线程共享全局变量还有静态变量等数据,而进程之间的通信需要以通信的方式进行(IPC),不过如何处理好同步与互斥,是编写多线程程序的难点
6.多线程的代码结构比多进程的代码结构简单易读

进程同步

互斥锁

互斥锁使用步骤:
1、定义一个互斥锁(变量)pthread_mutex_t mutex
2、初始化锁:预设互斥锁的初始值 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;int respthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr)
功能:初始化定义的互斥锁(就是设置互斥锁所需要的值)
返回值:总是返回0;所以这个函数不需要进行错误处理
参数:mutex:互斥锁:需要我们定义
3、加锁解锁
pthread_mutex lock(&mutex);(阻塞加锁)访问临界区加锁操作
pthread_mutex_trylock()(非阻塞加锁)当锁被占用时返回EBUSY而不是挂起等待
pthread_mutex_unlock(&mutex)访问临界区解锁

4、进程退出时销毁互斥锁

线程信号量

线程信号量的使用步骤:
1、定义信号量集合
sem_t sem【3】
线程信号量集合其实就是一个数组,数组每个元素就是一个信号量(sem【0】:第一个信号量 ; sem【1】:第二个人信号量 ; sem【2】:第三个信号量)
2、初始化集合中的每个信号量
#include<semaphore.h>
int sem_init(sem_t *sem,int pthread,unsigned int value)
功能:
初始化线程信号量集合中的某个信号量,给它设置一个初值
返回值:成功返回0,失败返回-1,errno被设置
信号量的错误号不是返回的,而是直接设置到errno
value:初始化值(对于二进制信号量来说,要么是1,要么是0)
pshared:0:给线程使用,!0可以给进程使用

3、p、v操作
P:int sem wait(sem tsem);
int sem trywait(sem tsem);
int sem timedwait(sem tsem,const struct timespec *abs timeout);
在这里插入图片描述
练习:线程1输出11111,线程2输出22222,线程3输出33333

4、进程结束时,删除线程信号量集合

条件变量

和互斥锁配合使用
练习:一条线程做自加,一条线程输出(当自加变量到5输出之后自加变量清零)

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

int count = 0;
pthread_mutex_t mutex;
pthread_cond_t cond;
void *add_1(void *arg)
{
    while(1)
    {
	pthread_mutex_lock(&mutex);
	count++;
	if(count == 5)
	{
	    pthread_cond_signal(&cond);
	}
	pthread_mutex_unlock(&mutex);
	sleep(1);
    }
}

void *print (void *arg)
{
    while(1)
    {
	pthread_mutex_lock(&mutex);
	if(count != 5)
	{
	    pthread_cond_wait(&cond, &mutex);
	}
	printf("cound = %d\n",count);
	count = 0;
	pthread_mutex_unlock(&mutex);
	sleep(1);
    }
}

int main()
{

    pthread_t id1;
    pthread_t id2;

    int ret;

    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);
    ret = pthread_create(&id1,NULL,add_1,NULL);
    if(0 != ret)
    {
	perror("thread create error!\n");
	exit(0);
    }

    ret = pthread_create(&id2,NULL,print ,NULL);
    if(0 !=ret)
    {
	perror("thread create error!\n");
	exit(0);
    }
    pthread_join(id1,NULL);
    pthread_join(id2,NULL);
    return 0;
}

在这里插入图片描述

条件变量的主要作用(线程协同):主线程对count+1,次线程发现当count ==5时输出count的值并将count清零
多线程配合工作时,当线程检测到某条件不满足时就休眠,直到别的线程将条件准备好,然后通过条件变量将其叫醒
使用步骤:
1、定义一个条件变量
pthread_cond_t
2、初始化
pthread_cond_init(pthread_cond_t *restrict cond,const pthread condattr_t *restrict attr );
功能
初始化条件变量,与互斥锁化类似
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
返回值:成功返回0,不成功返回非零错误号
参数:
cond:条件变量
attr:属性一般是NULL
3、使用条件变量
4、删除条件变量,也需要把互斥锁删除

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值