linux网络编程----->线程同步-->条件变量

简介:

开发使用多线程过程中, 不可避免的会出现多个线程同时操作同一块共享资源, 当操作全部为读时, 不会出现未知结果, 一旦当某个线程操作中有写操作时, 就会出现数据不同步的事件. 

    而出现数据混乱的原因:


    • 资源共享(独享资源则不会)

    • 调试随机(对数据的访问会出现竞争)

    • 线程间缺少必要的同步机制   

    以上三点, 前两点不能被改变. 欲提高效率, 传递数据, 资源必须共享. 只要资源共享, 就一定会出现线程间资源竞争, 只要存在竞争关系, 数据就会出现混乱.

    所以只能从第三点着手, 使多个线程在访问共享资源的时候, 出现互斥.

线程同步:

    指在一定的时间里只允许某一个进程访问某个资源,而在此时间内,不允许其它线程对该资源进行操作.

    

线程的同步机制:

    • 互斥量(互斥锁)

    • 读写锁

    • 条件变量(需要配合互斥量(互斥锁)来使用)

    • 信号量        


    由于前章节介绍完了互斥量(互斥锁)和读写锁,  本次介绍条件变量


    条件变量(需要配合互斥量(互斥锁)来使用):

        条件变量本身不是锁! 但它可以造成阻塞.通常与互斥量(互斥锁)一起使用,给多线程提供一个会合的场所.给互斥量(互斥锁)一层包装.

    条件变量主要用的API:

      初始化条件变量

        pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);   

           参数1:cond 传入的一个条件变量地址

           参数2:attr 表示条件变量的属性,没有特殊需求一般填NULL

           restrice: C99标准类型限定符, 用于告诉编译器,该指向的对象已被引用,不能被除该指针外的所有直接或间接的方法修改该指向的内容.

     

     销毁一个条件变量      

        pthread_cond_destroy(pthread_cond_t* cond);    

           参数: cond 传入的一个条件变量地址

        

     阻塞等待一个条件变量

        pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);   

           参数1: cond传入一个已经初始好的条件变量地址

           参数2: mutex传入一个已经初始化好的互斥量(互斥锁)

           restrice: C99标准类型限定符, 用于告诉编译器,该指向的对象已被引用,不能被除该指针外的所有直接或间接的方法修改该指向的内容.

        函数作用:

            1.阻塞等待条件变量(参1)满足

            2.释放已掌握的护持锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);

                    1. 2两步为一个原子操作

            3.当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取护持锁;


      限时等待一个条件变量:

        pthread_cond_timewait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime);

           参数1: cond传入一个已经初始好的条件变量地址

           参数2: mutex传入一个已经初始化好的互斥量(互斥锁)

           参数3: abstime传入一个绝对时间解构体, struct timespes结构体

                                        struct timespec{

                                                time_t tv_sec;        /*seconds*/ 秒

                                                long tv_nsec;        /*nanosecondes*/    纳秒


            唤醒至少一个阻塞在条件变量上的线程

                  pthread_cond_signal(pthread_cond_t* cond);

                        参数: cond传入一个已经初始好的条件变量地址


     唤醒全部阻塞在条件变量上的线程

        pthread_cond_broadcast(pthread_cond_t* cond);

            参数: cond传入一个已经初始好的条件变量地址


     案例: 

       程同步典型的案例即为生产者消费者模型,而借助条件变量来实现这一模型,是比较常见的一种方法。假定有两个线程,一个模拟生产者行为,一个模拟消费者行为。两个线程同时操作一个共享资源(一般称之为汇聚),生产向其中添加产品,消费者从中消费掉产品。

      

        看如下示例,使用条件变量模拟生产者、消费者问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
 
//链表节点结构体
struct  msg{
     struct  msg* next;  //指针域
     int  num;        //数据域
};
 
struct  msg* head;  //全局头指针
 
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
 
void * consumer( void * args){
     struct  msg* mp = NULL;   //创建一个节点指针
     for (;;){     //无限循环
         pthread_mutex_lock(&lock);   //加锁
         //?为何为while不为if, 
         //如果消费者或其它线程提早调用了pthread_cond_signal,而没有产生数据
         //而此时头指针还是为空, if会造成程序崩溃
         while (NULL == head){   //头指针为空,说明没有数据
             pthread_cond_wait(&has_product, &lock);
         }
         mp = head;     //获取数据节点
         head = mp->next;    //模拟消费一个产品
         pthread_mutex_unlock(&lock);
 
         printf ( "-Consume --%d\n" , mp->num);  //打屏提示
         free (mp);    //释放
         sleep( rand () % 5);     //等待一段时间
     }
}
 
void * producer( void * args){
     struct  msg* mp = NULL;
     for (;;){
         //生产一个产品
         mp = ( struct  msg*) malloc ( sizeof ( struct  msg));
         mp->num =  rand () % 1000 + 1;  //1-1000之间
 
         printf ( "-Produce ---%d\n" , mp->num);
 
         pthread_mutex_lock(&lock);   //加锁
         mp->next = head;
         head = mp;     //头插法加入产品链表
         pthread_mutex_unlock(&lock);     //解锁
         //将等待在该条件变量的线程唤醒
         pthread_cond_signal(&has_product);
         sleep( rand ()%5);     //等待
     }
}
 
int  main( int  argc,  char * argv[]){
     pthread_t pid, cid;
     srand ( time (NULL));  //随机数种子
 
     pthread_create(&pid, NULL, producer, NULL);  //创建一个生产者线程
     pthread_create(&cid, NULL, consumer, NULL);  //创建一个消费者线程
 
     pthread_join(pid, NULL); //等待消费者线程结束
     pthread_join(cid, NULL); //等待生产者线程结束
     return  0;
}

运行结果:

    wKioL1diwc3ACPOoAABADT7jHoo417.png-wh_50





      本文转自asd1123509133 51CTO博客,原文链接:http://blog.51cto.com/lisea/1790097,如需转载请自行联系原作者







相关文章
|
17天前
|
安全 Linux 虚拟化
网络名称空间在Linux虚拟化技术中的位置
网络名称空间(Network Namespaces)是Linux内核特性之一,提供了隔离网络环境的能力,使得每个网络名称空间都拥有独立的网络设备、IP地址、路由表、端口号范围以及iptables规则等。这一特性在Linux虚拟化技术中占据了核心位置🌟,它不仅为构建轻量级虚拟化解决方案(如容器📦)提供了基础支持,也在传统的虚拟机技术中发挥作用,实现资源隔离和网络虚拟化。
网络名称空间在Linux虚拟化技术中的位置
|
17天前
|
网络协议 安全 Linux
Linux网络名称空间之独立网络资源管理
Linux网络名称空间是一种强大的虚拟化技术🛠️,它允许用户创建隔离的网络环境🌐,每个环境拥有独立的网络资源和配置。这项技术对于云计算☁️、容器化应用📦和网络安全🔒等领域至关重要。本文将详细介绍在Linux网络名称空间中可以拥有的独立网络资源,并指出应用开发人员在使用时应注意的重点。
|
15天前
|
存储 算法 Linux
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
【实战项目】网络编程:在Linux环境下基于opencv和socket的人脸识别系统--C++实现
39 6
|
5天前
|
机器学习/深度学习 缓存 监控
linux查看CPU、内存、网络、磁盘IO命令
`Linux`系统中,使用`top`命令查看CPU状态,要查看CPU详细信息,可利用`cat /proc/cpuinfo`相关命令。`free`命令用于查看内存使用情况。网络相关命令包括`ifconfig`(查看网卡状态)、`ifdown/ifup`(禁用/启用网卡)、`netstat`(列出网络连接,如`-tuln`组合)以及`nslookup`、`ping`、`telnet`、`traceroute`等。磁盘IO方面,`iostat`(如`-k -p ALL`)显示磁盘IO统计,`iotop`(如`-o -d 1`)则用于查看磁盘IO瓶颈。
|
1天前
|
存储 Linux Shell
Linux|Awk 变量、数字表达式和赋值运算符
Linux|Awk 变量、数字表达式和赋值运算符
6 2
|
3天前
|
网络协议 Linux Shell
【linux网络(一)】初识网络, 理解四层网络模型
【linux网络(一)】初识网络, 理解四层网络模型
|
3天前
|
安全 Ubuntu Linux
Linux 网络操作命令Telnet
Linux 网络操作命令Telnet
16 0
Linux 网络操作命令Telnet
|
3天前
|
固态存储 Ubuntu Linux
Linux(29) 多线程快速解压缩|删除|监视大型文件
Linux(29) 多线程快速解压缩|删除|监视大型文件
11 1
|
3天前
|
Ubuntu Linux
Linux(22) Linux设置网络优先级顺序
Linux(22) Linux设置网络优先级顺序
6 0
|
4天前
|
Ubuntu 网络协议 Linux
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
Linux(20) Ubuntu 20.04 网络接口自动切换路由配置
27 0