进程间通信:通俗理解信号量方式

本文通过火车卫生间的实例,深入浅出地解释了信号量的基本概念及其作用,并提供了信号量在程序中的具体应用示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于名字,老师课件上写信号量,实验教材上却写信号灯。这种概念,叫来叫去的概念的东西适合不去理解东西的女生去背。然后觉得知道的东西很多一样每次都说其中一个时都把另一个名字也说出来。

          我喜欢通俗的理解一下,在前两遍的时候没有什么概念,这次就仔细找生活中的概念。我想起来我坐过的火车,那上边的卫生间,目前没坐过硬座以外的火车,就拿我见过的来说吧。卫生间绝对算是一个临界资源了,这个很好理解,它就一个xx,所以一次只能一个人(进程)上(访问)。

          那个能亮“有人”的指示灯的作用就很好理解,没人的时候是不亮的,有人的时候立即显示“有人”。其它人就不能访问。这不就是一个活生生的信号量例子。那一车厢的人就是进程,他们都要上一个只能一个人同时上的卫生间。

         同样在火车上上厕所也能总结出步骤来:1建好厕所和指示灯 2将灯设为无人状态 3一人进厕所 灯显示为“有人”状态 4 方便完 出来 灯重新显示为“无人”状态 5 拆出厕所和指示灯。其实上边的第一步和第五步是为了引到信号量中硬套上去的,没有人会这样做。 

         根据火车上上厕所的经历,信号量的作用和用法都出来了。

         比喻完了,就该说点正经的,在没学习这个的时候就在mini2440的adc驱动和tc驱动之间看到了信号量的踪迹。但是那是驱动程序,那也算是进程吗?这都还是未解的。

在这期间老师给我举了一个高雅的例子:打印机。不过意思是相同的。

         看一个例子:test.c

#include <stdio.h>  
#include <sys/types.h>  
#include <sys/ipc.h>  
#include <sys/sem.h>  
#include <stdlib.h>  
#include <math.h>  
#include <errno.h>  
#include <unistd.h>  
int main()  
{  
    int pid, semid;  
    key_t semkey;  
    int val;  
    if((semkey = ftok("./test.c",1))<0)  
    {  
        printf("ftok failed\n");  
        exit(EXIT_FAILURE);  
    }  
    printf("ftok ok, semkey = %d\n", semkey);  
      
    if((semid = semget(semkey, 1, IPC_CREAT|IPC_EXCL|0700))<0)  
    {  
        printf("semget failed\n");  
        exit(EXIT_FAILURE);  
    }  
    printf("semget ok, semid=%d\n", semid);  
      
    if((semctl(semid, 0, SETVAL, 1))<0)  
    {  
        printf("semctl set semval failed\n");  
        exit(EXIT_FAILURE);  
    }  
    printf("semctl set semval ok\n");  
      
    if((pid = fork())<0)  
    {  
        printf("fork failed\n");  
        exit(EXIT_FAILURE);  
    }  
    else if(pid>0)  
    {  
        struct sembuf p_op_buf, v_op_buf;  
        p_op_buf.sem_num = 0;  
        p_op_buf.sem_op = -1;  
        if(semop(semid, &p_op_buf, 1)<0)  
        {  
            printf("semop failed\n");  
            exit(EXIT_FAILURE);  
        }  
          
        printf("father get the semaphore\n");  
        v_op_buf.sem_num = 0;  
        v_op_buf.sem_op = 1;  
        v_op_buf.sem_flg = 0;  
        if(semop(semid, &v_op_buf, 1)<0)  
        {  
            printf("semop release semaphore failed\n");  
            exit(EXIT_FAILURE);  
        }  
        wait(NULL);  
    }  
    else  
    {  
        struct sembuf p_op_buf, v_op_buf;  
        sleep(1);  
        printf("child wait for the semaphore\n");  
        p_op_buf.sem_num = 0;  
        p_op_buf.sem_op = -1;  
        p_op_buf.sem_flg = 0;  
        if(semop(semid, &p_op_buf, 1)<0)  
        {  
            printf("semop get semaphore failed\n");  
            exit(EXIT_FAILURE);  
        }  
        printf("child get the semaphore\n");  
        if(semctl(semid, 0, IPC_RMID, 0)< 0)  
        {  
            printf("semctl remove semaphore set failed\n");  
            exit(EXIT_FAILURE);  
        }  
      
    }  
    return 0;  
}  

运行结果:

[root@localhost Desktop]# ./a.out   
ftok ok, semkey = 16795729  
semget ok, semid=163843  
semctl set semval ok  
father get the semaphore  
child wait for the semaphore  
child get the semaphore  
[root@localhost Desktop]#  

 在做完这个例子后我其实不能明白这个在这里边的作用,一个进程获取一下然后释放。另一个进程同样这样做。真没有什么意思。但是我想到了 adc 和 tc的例子。它们只是同时要用,然后信号量就有了,又但是不是说只让一个用,而不让另一个用,而是做一个调解。让一个进程用一下。再让另一个用一下,这样就不会造成某个进程不能用这个资源 了,上边的程序运行一次真没有什么意思。如果多次意思就出来了。

         另外关于 计数信号灯 这个现实中的例子莫过于是一个生意很好的饭店中的空的桌子的数量了,人特别多,都在外边排队,50张桌子递减,来一桌人就减一,到0的时候就不能再进人了,如果走一桌又从0+1=1了,就可以再进一桌人了。这个资源是可以这样来的。

转自:https://blog.youkuaiyun.com/kangear/article/details/8510812
<think>嗯,用户想了解进程间通信(IPC)的实现方法,我需要整理相关知识。首先,进程间通信有哪些常见方式呢?根据之前的引用,有Intent、AIDL、Messenger、Socket、共享内存、管道等。应该逐一介绍每种方法的原理、优缺点和应用场景。 需要确保每个部分结构清晰,可能分成几个小节,每个方法单独说明。比如Intent通常用于Android中传递数据,而管道则基于文件描述符,适合父子进程。共享内存高效但需要处理同步问题,Socket适用于网络通信。 用户提到需要生成相关问题,可能涉及比较不同方法、如何选择合适的方法,或者具体的实现步骤。比如优缺点对比,或者实际应用例子。 还要注意引用对应的参考文献,比如引用[1]提到AIDL和Messenger,引用[2]讲管道,引用[3]共享内存,引用[4]Socket。在介绍每种方法时,末尾加上对应的引用标识。 另外,用户要求使用中文回答,数学公式用$...$,独立公式用$$...$$。但在这个问题中可能数学公式较少,但如果有的话要正确应用,比如在共享内存中可能需要同步机制,涉及信号量的话可以用公式表示P/V操作。 需要确保每个实现方式的解释准确,同时语言通俗易懂。比如解释Binder机制时,可以提到它是Android特有的,基于内存映射,效率高。而Socket则更通用,支持跨设备通信。 最后生成的相关问题要覆盖不同方面,比如优缺点对比、应用场景、具体实现步骤等,帮助用户深入理解。</think>### 进程间通信(IPC)实现方法详解 进程间通信(IPC)是操作系统和分布式系统中实现多进程协作的关键技术。以下是常见的实现方式及其原理、优缺点和应用场景: --- #### 1. **Intent(Android特有)** - **原理**:通过封装数据(如字符串、对象)在不同组件(如Activity、Service)间传递,常用于Android系统内的轻量级通信[^1]。 - **优点**:简单易用,支持跨进程组件通信。 - **缺点**:传输数据量受限,不支持复杂类型直接传递。 - **示例**: ```java Intent intent = new Intent(context, TargetActivity.class); intent.putExtra("key", "value"); startActivity(intent); ``` --- #### 2. **AIDL(Android接口定义语言)** - **原理**:基于Binder机制,通过定义接口实现跨进程方法调用。服务端实现接口,客户端通过代理对象调用远程方法[^1]。 - **优点**:支持复杂数据类型和方法调用,适用于高频通信。 - **缺点**:实现较复杂,需处理线程同步问题。 - **代码结构**: ```java // AIDL接口定义 interface IMyService { int add(int a, int b); } ``` --- #### 3. **管道(Pipe)** - **原理**:基于文件描述符的单向通信,通常用于父子进程间通信。例如: $$ \text{父进程} \rightarrow \text{写端} \quad \text{子进程} \rightarrow \text{读端} $$ - **优点**:实现简单,适合小数据量传输[^2]。 - **缺点**:单向通信,效率较低。 - **示例**: ```c int fd[2]; pipe(fd); // 创建管道 if (fork() == 0) { read(fd[0], buffer, sizeof(buffer)); // 子进程读 } else { write(fd[1], "data", 4); // 父进程写 } ``` --- #### 4. **共享内存(Shared Memory)** - **原理**:多个进程映射同一块物理内存区域,直接读写数据,需通过信号量或锁实现同步[^3]。 - **优点**:速度最快,适合大数据量交换。 - **缺点**:需手动处理竞态条件。 - **同步公式**: $$ P(S): S \leftarrow S - 1 \quad (\text{if } S \geq 0) $$ $$ V(S): S \leftarrow S + 1 $$ - **示例**: ```c shm_id = shmget(KEY, SIZE, IPC_CREAT); shared_mem = shmat(shm_id, NULL, 0); ``` --- #### 5. **Socket通信** - **原理**:基于网络套接字(如TCP/UDP),支持跨设备通信。通过以下函数创建: ```c int socket(int domain, int type, int protocol); // 引用[4] ``` - **优点**:跨平台、跨网络,灵活性高。 - **缺点**:协议开销较大,延迟较高。 - **示例**(Python): ```python # 服务端 import socket s = socket.socket() s.bind(('localhost', 8080)) s.listen() ``` --- #### 6. **消息队列(Message Queue)** - **原理**:内核维护的链表结构,进程通过消息类型发送/接收数据。 - **优点**:异步通信,支持多对多交互。 - **缺点**:消息大小受系统限制。 --- ### 如何选择IPC方法? 1. **数据量小且简单**:优先选Intent或管道。 2. **高频复杂调用**:使用AIDL或共享内存。 3. **跨网络通信**:必须用Socket。 4. **需高并发控制**:结合共享内存与信号量。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值