linux网络编程----->线程同步-->信号量

简介:

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

    而出现数据混乱的原因:


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

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

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

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

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

线程同步:

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

    

线程的同步机制:


    • 互斥量(互斥锁)

    • 读写锁

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

    • 信号量        

    前两章已经介绍完了互斥量(互斥锁),读写锁,和条件变量, 本章来介绍重点的信号量


    信号量又称进化版的互斥锁----> 互斥锁只能同时有一个线程进行访问,而信号量可以同时有N个线程同时进行.

    由于互斥锁的粒度比较大,如果我们希望在多个线程间结某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住.这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形之中导致线程的并发性下降.线程从并行执行,变成了串形执行.与直接使用单进程无异.

    信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发性.


    首先来看看条件变量所常用的函数:

        sem_init(sem_t* sem, int pshared, unsigned int value); 

            作用:初始化一个信号量

            参数1: sem信号量

            参数2: pshared 取0用于线程间,取非0(一般为1)用于进程间

            参数3: value 指定信号量的初值


        sem_destroy(sem_t* sem);

            作用:销毁一个信号量

            参数: 指定一个已经初始化的sem信号量


        sem_wait(sem_t* sem);

            作用:给信号量加锁(对信号量的值作--操作,如果此时信号量的值已为0 阻塞等待)

            参数:指定一个已经初始的sem信号量


        sem_post(sem_t* sem);

            作用:给信号量解锁(对信号量的值作++操作)

            参数:指定一个已经初始的sem信号量


        sem_trywait(sem_t* sem);

            作用:尝试对信号量加锁(如果此时信号量的值已为0,立即返回.不会阻塞)

            参数:指定一个已经初始的sem信号量


        sem_timedwait(sem_t* sem, const struct timespec* abs_timeout);

            作用:限定时间内对信号量尝试加锁(时间为当前绝对时间)

            参数1: 指定一个已经初始化的sem信号量

            参数2: 指定绝对时间  结构体如下struct timespec{

                                                time_t tv_sec;    //秒

                                                long tv_nsec;     //纳秒

                                            };

        

        案例:一个线程读用户输入,另一个线程打印"hello world".如果用户无输入,则每隔5秒向屏幕打印一个"hello world";如果用户有输入,则立即打印"hello world"到屏幕[思考]

                           

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
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
#include <time.h>
#include <string.h>
 
sem_t sem;  //全局信号量
 
 
void * thread_handler( void * agrs){
     
     struct  timespec tv = {  time (NULL)+5, 0};   //初始化当前时间
     while (1){
         //定时获取信号量
         sem_timedwait(&sem, &tv);
         //如果用户有输入,立即打印, 否则5秒后打印
         printf ( "hello world\n" );
         //重新设置绝对时间
         tv.tv_sec =  time (NULL)+5;
         tv.tv_nsec = 0;
     }
}
 
int  main( int  argc,  char * agrv[]){
     pthread_t tid;
     //初始化信号量,支持线程间,开始初值为0
     sem_init(&sem, 0, 0);
 
     //创建线程
     pthread_create(&tid, NULL, thread_handler, NULL);
 
     char  buf[BUFSIZ] = { 0 };
     while (1){
         //阻塞读取用户输入
         fgets (buf,  sizeof (buf), stdin);
         //信号量值+1
         sem_post(&sem);
     }
 
     //等待线程退出
     pthread_join(tid, NULL);
             
     return  0;
}

提示:信号量在线程池中多有应用.务必熟练.






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




相关文章
|
消息中间件 Java Linux
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
2024年最全BATJ真题突击:Java基础+JVM+分布式高并发+网络编程+Linux(1),2024年最新意外的惊喜
|
网络协议 算法 Linux
【嵌入式软件工程师面经】Linux网络编程Socket
【嵌入式软件工程师面经】Linux网络编程Socket
872 1
|
消息中间件 Linux
Linux中的System V通信标准--共享内存、消息队列以及信号量
希望本文能帮助您更好地理解和应用System V IPC机制,构建高效的Linux应用程序。
784 48
|
消息中间件 Linux
Linux:进程间通信(共享内存详细讲解以及小项目使用和相关指令、消息队列、信号量)
通过上述讲解和代码示例,您可以理解和实现Linux系统中的进程间通信机制,包括共享内存、消息队列和信号量。这些机制在实际开发中非常重要,能够提高系统的并发处理能力和数据通信效率。希望本文能为您的学习和开发提供实用的指导和帮助。
1205 20
|
Linux
【Linux】System V信号量详解以及semget()、semctl()和semop()函数讲解
System V信号量的概念及其在Linux中的使用,包括 `semget()`、`semctl()`和 `semop()`函数的具体使用方法。通过实际代码示例,演示了如何创建、初始化和使用信号量进行进程间同步。掌握这些知识,可以有效解决多进程编程中的同步问题,提高程序的可靠性和稳定性。
1335 19
|
消息中间件 Linux 开发者
Linux进程间通信秘籍:管道、消息队列、信号量,一文让你彻底解锁!
【8月更文挑战第25天】本文概述了Linux系统中常用的五种进程间通信(IPC)模式:管道、消息队列、信号量、共享内存与套接字。通过示例代码展示了每种模式的应用场景。了解这些IPC机制及其特点有助于开发者根据具体需求选择合适的通信方式,促进多进程间的高效协作。
919 3
linux内核 —— 读写信号量实验
linux内核 —— 读写信号量实验
|
开发者 API Windows
从怀旧到革新:看WinForms如何在保持向后兼容性的前提下,借助.NET新平台的力量实现自我进化与应用现代化,让经典桌面应用焕发第二春——我们的WinForms应用转型之路深度剖析
【8月更文挑战第31天】在Windows桌面应用开发中,Windows Forms(WinForms)依然是许多开发者的首选。尽管.NET Framework已演进至.NET 5 及更高版本,WinForms 仍作为核心组件保留,支持现有代码库的同时引入新特性。开发者可将项目迁移至.NET Core,享受性能提升和跨平台能力。迁移时需注意API变更,确保应用平稳过渡。通过自定义样式或第三方控件库,还可增强视觉效果。结合.NET新功能,WinForms 应用不仅能延续既有投资,还能焕发新生。 示例代码展示了如何在.NET Core中创建包含按钮和标签的基本窗口,实现简单的用户交互。
549 0
|
关系型数据库 Linux 数据库
linux设置信号量系统参数
linux设置信号量系统参数
413 0
|
Linux
【Linux】生产者消费者模型——环形队列RingQueue(信号量)
【Linux】生产者消费者模型——环形队列RingQueue(信号量)
388 0