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

    技术2026-08-18  10

    在学习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,转载请注明出处。

    Processed: 0.014, SQL: 9