Linux系统编程——09-linux-day09(线程同步)

在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

09-linux-day09(线程同步)

 

 

一、内容回顾

1、守护进程:运行在后台,脱离终端,周期性执行某些任务

会话:多个进程组组成一个会话,组长进程不能创建会话。

进程组:多个进程在同一个组,第一个进程默认是组长

守护进程的步骤:

(1)创建子进程,父亲退出(孤儿进程)

(2)创建会话,当会长

(3)切换目录

(4)设置掩码

(5)关闭文件描述符

(6)执行核心逻辑

(7)退出

nohup & 把进程放入后台运行

 

2、多线程:

线程是轻量级的进程,最小的执行单位,进程是最小的资源申请单位。一个进程里可以有多个线程。

创建线程 pthread_create

回收线程 pthred_join

线程退出 pthread_exit void *retval

杀死线程 pthread_cancel 取消点

线程分离 pthread_detach,也可以通过属性设置

pthread_attr_setdetachstate 设置属性分离,之前需要pthread_attr_init初始化,之后需要pthread_attr_destroy销毁

查看线程ID:pthread_self 在进程内唯一

 

二、学习目标

1、熟练掌握互斥量的使用

2、说出什么叫死锁以及解决方案

3、熟练掌握读写死锁的使用

4、熟练掌握条件变量的使用

5、理解条件变量实现的生产者消费者模型

6、理解信号量实现的生产者消费者模型

 

三、线程同步

1、互斥量的使用

》互斥量

两个线程访问同一块共享资源,如果不协调顺序,容易造成数据混乱。

>加锁 mutex

pthread_mutex_init 初始化

pthread_mutex_destroy 摧毁

pthread_mutex_lock 加锁

pthread_mutex_unlock(pthread_mutex_t *mutex) 解锁

》互斥量的使用步骤:

1)初始化

2)加锁

3)执行逻辑——操作共享数据

4)解锁

注意事项:

  加锁需要最小力度,不要一直占用临界区。

 

解决昨天的问题——模拟线程共同抢占(屏幕)资源

>vi pthread_print.c

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 #include<pthread.h>
 4 #include<stdlib.h>
 5 
 6 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 7 
 8  9 
10 void* thr1(void *arg){
11     while(1){
12         //先上锁
13         pthread_mutex_lock(&mutex);//加锁:当有线程已经加锁的时候会阻塞
14         //临界区
15         printf("hello");//不带换行,没有行缓冲,输出不出来
16         sleep(rand()%3);
17         printf("world\n");
18         //释放锁
19         pthread_mutex_unlock(&mutex);
20         sleep(rand()%3);
21     }
22 }
23 
24 void* thr2(void *arg){
25     while(1){
26         //先上锁
27         pthread_mutex_lock(&mutex);
28         //临界区
29         printf("HELLO");
30         sleep(rand()%3);
31         printf("WORLD\n");
32         //释放锁
33         pthread_mutex_unlock(&mutex);
34         sleep(rand()%3);
35     }
36 }
37 
38 int main(int argc, char *argv[])
39 {
40     //创建两个线程,回收两次
41     pthread_t tid[2];
42     pthread_create(&tid[0],NULL,thr1,NULL);
43     pthread_create(&tid[1],NULL,thr2,NULL);
44     
45     pthread_join(tid[0],NULL);
46     pthread_join(tid[1],NULL);
47     
48     return 0;
49 }

>make

>./pthread_print

 

》尝试加锁

man pthread_mutex_trylock

int pthread_mutex_trylock(pthread_mutex_t *mutex);

测试(已经加锁的再次尝试加锁结果会怎么样?)

>touch mutex_trylock.c

>vi mutex_trylock.c

 1 #include<stdio.h>
 2 #include<unistd.h>
 3 #include<pthread.h>
 4 #include<string.h>
 5 
 6 pthread_mutex_t mutex;
 7 
 8 void *thr(void *arg)
 9 {
10     while(1){
11         pthread_mutex_lock(&mutex);
12         printf("hello world\n");
13         sleep(30);
14         pthread_mutex_unlock(&mutex);
15     }
16     return NULL;
17 }
18 
19 int main(int argc, char *argv[])
20 {
21     pthread_mutex_init(&mutex,NULL);
22     pthread_t tid;
23     pthread_create(&tid,NULL,thr,NULL);
24     sleep(1);
25     while(1){
26         int ret = pthread_mutex_trylock(&mutex);
27         if(ret > 0){
28             printf("ret = %d,errmmsg:%s\n",ret,strerror(ret));
29         }
30         sleep(1);
31     }
32     
33     return 0;
34 }

>make

>./mutex_trylock

(打印完hellow world后,一直打印:ret = 16,errmsg:Device or resource busy)

可以在以下文件查看errno的错误信息

 

2、死锁

》死锁

  锁了又锁,自己加了一次锁成功,又加了一次锁。

   交叉锁(解决办法:每个线程申请锁的顺序要一致。如果申请到一把锁,申请另外一把的时候申请失败,应该释放已经掌握的。)

注意:互斥量只是建议锁。

 

3、读写锁

》读写锁

  与互斥量类似,但读写锁允许更高的并行性。其特点为:读共享,写独占,写优先级高。

》读写锁状态:

三种状态:

  1)读模式下加锁状态(读锁)

  2)写模式下加锁状态(写锁)

  3)不加锁状态

》读写锁特性:

1)读写锁是“写模式加锁”时,解锁前,所有对该锁加锁的线程都会被阻塞。

2)读写锁是“读模式加锁”时,如果线程以读模式对其加锁会成功;如果线程以写模式加锁会阻塞。

3)读写锁是“读模式加锁”时,既有试图以写模式加锁的线程,也有试图以读模式加锁的线程。那么读写锁会阻塞随后的读模式锁请求。优先满足写模式锁。读锁、写锁并行阻塞,写锁优先级高。

读写锁也叫共享-独占锁。当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的。读共享,写独占。

》读写锁的使用场景:非常适合于对数据结构读的次数远大于写的情况。

》读写锁场景练习:

1)线程A加写锁成功,线程B请求读锁

  B阻塞

2)线程A持有读锁,线程B请求写锁

  B阻塞

3)线程A拥有读锁,线程B请求读锁

  B加锁成功

4)线程A持有读锁,然后线程B请求写锁,然后线程C请求写锁

  BC阻塞;A释放后,B加锁;B释放后,C加锁

5)线程A持有写锁,然后线程B请求读锁,然后线程C请求写锁

  BC阻塞;A释放后,C加锁;C释放后,B加锁

 

初始化:

int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;

 

4、条件变量介绍和生产者和消费者模型

 

 

5、条件变量生产者消费者模型实现

 

6、条件变量生产者和消费者模型演示

 

7、信号量的概念和函数

 

8、信号量实现生产者和消费者分析

 

9、信号量实现生产者和消费者

 

10、文件锁单开进程

 

11、哲学家就餐模型分析

 

 

 

在学习Linux系统编程总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
资源包主要包含以下内容: ASP项目源码:每个资源包中都包含完整的ASP项目源码,这些源码采用了经典的ASP技术开发,结构清晰、注释详细,帮助用户轻松理解整个项目的逻辑和实现方式。通过这些源码,用户可以学习到ASP的基本语法、服务器端脚本编写方法、数据库操作、用户权限管理等关键技术。 数据库设计文件:为了方便用户更好地理解系统的后台逻辑,每个项目中都附带了完整的数据库设计文件。这些文件通常包括数据库结构图、数据表设计文档,以及示例数据SQL脚本。用户可以通过这些文件快速搭建项目所需的数据库环境,并了解各个数据表之间的关系和作用。 详细的开发文档:每个资源包都附有详细的开发文档,文档内容包括项目背景介绍、功能模块说明、系统流程图、用户界面设计以及关键代码解析等。这些文档为用户提供了深入的学习材料,使得即便是从零开始的开发者也能逐步掌握项目开发的全过程。 项目演示与使用指南:为帮助用户更好地理解和使用这些ASP项目,每个资源包中都包含项目的演示文件和使用指南。演示文件通常以视频或图文形式展示项目的主要功能和操作流程,使用指南则详细说明了如何配置开发环境、部署项目以及常见问题的解决方法。 毕业设计参考:对于正在准备毕业设计的学生来说,这些资源包是绝佳的参考材料。每个项目不仅功能完善、结构清晰,还符合常见的毕业设计要求和标准。通过这些项目,学生可以学习到如何从零开始构建一个完整的Web系统,并积累丰富的项目经验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值