进程间通讯与同步的实现

进程通讯

  • 内存共享

    A进程创建共享区 shmget(…) 映射内存共享区 shmat(…)

    B进程通过key找到共享区 映射内存共享区

    进程间通讯

    撤销各自的内存映射 shmdt()

    删除共享区 shctl()

  • 管道Pipe

    A进程与B进程进行相互通讯 需要建立两个管道

    当A->B时,需要在A中write end 在B中read end;当写入满时,管道阻塞;当管道无东西看读时 同样阻塞;

***以下代码为Xcode上的实现 因为VS下不支持某些类库 ***
//
//  main.c
//  PipeSample
//
//  Created by Lean on 15/8/2.
//  Copyright (c) 2015年 WB. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>//提供 wait函数
#include <unistd.h>//提供进程
#include <string.h>

int main(int argc, const char * argv[]) {

    int pipe_fd[2];//管道的read end和write end
    pid_t child_pid;
    char pipe_buf;
    //初始化
    memset(pipe_fd, 0, sizeof(int)*2);
    //通过pipe打开读写端口,因为管道是单向性的 所以需要两条管道
    if (pipe(pipe_fd)==-1)
        return -1;
    //fork一个子进程
    child_pid=fork();
    if (child_pid==-1)
        return -1;

    if (child_pid==0) {
        //关闭写端
        close(pipe_fd[1]);
        while (read(pipe_fd[0], &pipe_buf,1)>0) {
            write(STDOUT_FILENO, &pipe_buf, 1);
        }
        close(pipe_fd[0]);
    }else{
        close(pipe_fd[0]);
        write(pipe_fd[1], "H", 1);
        write(pipe_fd[1], "k", 1);
        close(pipe_fd[1]);
        wait(NULL);
    }
    return 0;

}
  • Unix Domain Socket(UDS)

服务端监听IPC请求

客户端发起IPC请求

建立IPC连接

客户端向服务端发送数据

************以下代码为示例代码 非运行代码**********
//
//  svr_for_uds.c
//  PipeSample
//
//  Created by Lean on 15/8/2.
//  Copyright (c) 2015年 WB. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/types.h>

#define UDS_PATH "uds_test"
#define BUFF_SIZE 100

int uds_client()
{
    int socket_client=-1;
    int data_len=0;
    size_t addr_size=0;
    struct sockaddr_un addr_srv;
    char str[100];
    memset(str, 0, sizeof(char)*100);
    strcpy(str, "This is the test for UDS");

    if ((socket_client=socket(AF_UNIX, SOCK_STREAM, 0))<0) {
        return -1;
    }
    addr_srv.sun_family=AF_UNIX;
    strcpy(addr_srv.sun_path,UDS_PATH);
    addr_size=offsetof(struct sockaddr_un, sun_path)+strlen(addr_srv.sun_path);
    if (connect(socket_client, (const struct sockaddr *)&addr_srv, addr_size)<0) {
        return -1;
    }
    if (send(socket_client, str, strlen(str), 0)<0) {
        close(socket_client);
        return -1;
    }
    if ((data_len=recv(socket_client, str, 100, 0))>0) {
        str[data_len]=‘\0‘;
        printf("echo from server :%s",str);
        return 0;
    }else{
        close(socket_client);
        return -1;
    }
}

int uds_server()
{
    int socket_srv=-1;
    int socket_client=-1;

    struct sockaddr_un addr_srv,addr_client;
    char str[BUFF_SIZE];
    memset(str,0, sizeof(char)*BUFF_SIZE);

    if ((socket_srv=socket(AF_UNIX,SOCK_STREAM, 0))<0) {
        return -1;
    }
    addr_srv.sun_family=AF_UNIX;
    strcpy(addr_srv.sun_path, UDS_PATH);
    if (bind(socket_srv, (struct sockaddr *)&addr_srv, offsetof(struct sockaddr_un,sun_path)+strlen(addr_srv.sun_path))<0) {
        return -1;
    }
    if (listen(socket_srv, 5)<0) {
        return -1;
    }
    while (1) {
        size_t nRecv;
        size_t sz=sizeof(addr_client);
        if ((socket_client=accept(socket_srv, (struct sockaddr *)&socket_client, &sz))==-1) {
            return -1;
        }
        if ((nRecv=recv(socket_client, str, 100, 0))<0) {
            close(socket_client);
            break;
        }
        if (send(socket_client, str, nRecv, 0)<0) {
            close(socket_client);
            break;
        }
        close(socket_client);
    }
    return 0;
}
  • Rremote Procedure Calls(RPC)

    客户端进程调用Stub接口

    Stub根据操作系统要求进行打包 并由内核来负责传输给服务器内核

    服务器端Stub进行解压并调用程序包匹配的进程

    服务端进程执行操作。

    服务器以以上的过程将结果传递给客户端。

    同步机制

  • 信号量Semaphore

    Semaphore S(信号量)指示共享资源的可用数量,初始化为1

    Operation P 也表达为wait()

    当进程想进入共享区执行P操作,减少S计数,如果计数>=0,则可以操作共享资源,

    否则则加入等待队列,直到某进程释放共享资源后,再从等待队列中取出某个资源。

    Operation V 也表达为signal()

    当进程想退出共享区执行V操作增加S计数,信号量加一,如果此时信号量>0,

    则说明没访问资源的等待者,直接返回。否则V操作要唤醒等待队列中的相关对象。

    例子:

    假设你有很多相互协作的进程,它们正在读或写一个数据文件中的记录。你可能希望严格协调对这个文件的存取,于是你使用初始值为1的信号量,

    在这个信号量上实施两个操作,首先测试并且给信号量的值减1,然后测试并给信号量的值加1。当第一个进程存取文件时,它把信号量的值减1,

    并获得成功,信号量的值现在变为0,这个进程可以继续执行并存取数据文件。但是,如果另外一个进程也希望存取这个文件,

    那么它也把信号量的值减1,结果是不能存取这个文件,因为信号量的值变为-1。这个进程将被挂起,直到第一个进程完成对数据文件的存取。

    当第一个进程完成对数据文件的存取,它将增加信号量的值,使它重新变为1,现在,等待的进程被唤醒,它对信号量的减1操作将获得成功。

  • 互斥体Mutex

    默认对信号量的操作为Counting Semaphore,而对于存取值为0/1的信号量成为Binary Semaphore,

    其表示一个资源是否被占用的两种状态

  • 管程Monitor

    管程是对信号量机制的延伸和改善,是一种更为轻便的同步手段。

    管程是可以被多个进程、线程安全访问的对象和模块,同时受Mutex保护,意味着同一时刻只能有一个访问者访问他们。

    实现管程机制的语言有Delphi,Java,Python,Ruby,C#等。

    特性:安全性 互斥性 共享性。

Android同步机制具体实现

  • Mutext 基于pthread接口的再封装。

    Android4.4.2源码/system/core/include/utils/Mutex.h

    lock() 获取资源锁 如果资源可用 函数马上返回 如果资源不可用 则形成阻塞

    unlock() 释放资源锁 如果有等待的进程 则唤醒等待的进程

    trylock() 获取资源锁 如果资源可用 则获取并返回0,如果资源不可用则返回并返回不为0.

inline Mutex::~Mutex() {
    pthread_mutex_destroy(&mMutex);
}
inline status_t Mutex::lock() {
    return -pthread_mutex_lock(&mMutex);
}
inline void Mutex::unlock() {
    pthread_mutex_unlock(&mMutex);
}
inline status_t Mutex::tryLock() {
    return -pthread_mutex_trylock(&mMutex);
}

AutoLock构造函数获取一个Binary Semaphore并对其加锁,析构函数对其Mutex解锁

class Autolock {
    public:
        inline Autolock(Mutex& mutex) : mLock(mutex)  { mLock.lock(); }
        inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }
        inline ~Autolock() { mLock.unlock(); }
    private:
        Mutex& mLock;
    };
  • Condition

    Android4.4.2源码/system/core/include/utils/Condition.h 依赖Mutex完成

    由于某个进程需要达到一定的条件才会执行某行代码,如果采用轮询的方法效率底下。Condition就是被设计为解决此类特殊的需求问题。

    wait() 等待某个条件满足,至于条件是什么,系统并不理会,相当于“黑盒”设计。

    enum WakeUpType {
        WAKE_UP_ONE = 0,
        WAKE_UP_ALL = 1
    };
        // Wait on the condition variable.  Lock the mutex before calling.
        //释放锁 睡眠 添加锁
    inline status_t Condition::wait(Mutex& mutex) {
        return -pthread_cond_wait(&mCond, &mutex.mMutex);
        }
    // same with relative timeout
    status_t waitRelative(Mutex& mutex, nsecs_t reltime);
    // Signal the condition variable, allowing one thread to continue.
    void signal();
    // Signal the condition variable, allowing all threads to continue.
    void broadcast();
    enum {
        PRIVATE = 0,
        SHARED = 1
    };
  • Barrier E:/Android4.4.2源码/frameworks/native/services/surfaceflinger/Barrier.h

    基于Mutext与Condition完成的一个模型。即“Barrier”是填充了条件的Condition。

    Barrier是专门为SurfaceFlinger而设计的。

    Mutex::Autolock _l(lock);保持操作原子性。

public:
    inline Barrier() : state(CLOSED) { }
    inline ~Barrier() { }
    void open() {
        Mutex::Autolock _l(lock);
        state = OPENED;
        cv.broadcast();
    }
    void close() {
        Mutex::Autolock _l(lock);
        state = CLOSED;
    }
    void wait() const {
        Mutex::Autolock _l(lock);
        while (state == CLOSED) {
                //释放锁 进入休眠 完了再获取锁
            cv.wait(lock);
        }
    }
private:
    enum { OPENED, CLOSED };
    mutable     Mutex       lock;
    mutable     Condition   cv;
    volatile    int         state;
};

参考文献:

Linux进程间通信之信号量(semaphore)、消息队列(Message Queue)和共享内存(Share Memory)

http://www.cnblogs.com/biyeymyhjob/archive/2012/11/04/2753535.html

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-10 00:57:37

进程间通讯与同步的实现的相关文章

C#进程间通讯技术-整理。

原文:C#进程间通讯技术-整理. 扩展阅读:http://www.cnblogs.com/joye-shen/archive/2012/06/16/2551864.html 一.进程间通讯的方式 1)共享内存 包括:内存映射文件,共享内存DLL,剪切板. 2)命名管道及匿名管道 3)消息通讯 4)利用代理方法.例如SOCKET,配置文件,注册表方式. 等方式. 方法一:通讯. 进程间通讯的方式有很多,常用的有共享内存(内存映射文件.共享内存DLL.剪切板等).命名管道和匿名管道.发送消息等几种方

进程间通讯。

进程间通信(IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法. 进程是计算机系统分配资源的最小单位(严格说来是线程).每个进程都有自己的一部分独立的系统资源,彼此是隔离的. 为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信. 举一个典型的例子,使用进程间通信的两个应用可以被分类为客户端和服务器(见主从式架构),客户端进程请求数据,服务端回复客户端的数据请求. 有一些应用本身既是服务器又是客户端,这在分布式计算中,

嵌入式OS入门笔记-以RTX为案例:八.RTX的进程间通讯(二)

嵌入式OS入门笔记-以RTX为案例:八.RTX的进程间通讯(二) RTX的进程间通讯主要依赖于四种机制,分别是事件(Event),互斥锁(Mutex),旗语或信号量(Semaphore),和邮箱(Mailbox).前三种机制侧重进程间的同步,邮箱则侧重进程间的数据通讯.这次讲一下信号量和邮箱. 1.信号量(Semaphore) 1.简介 信号量其实是一个很抽象的操作系统原语,它最早由荷兰计算机科学家Dijkstra提 出,用于解决多项资源的分配问题.实际上信号量的适用范围非常广,可以很好地解决很

进程间通讯

进程间通讯(Inter process communication :IPC) 1>6种进程间通讯: 4种数据共享机制:包括管道(分为无名管道和有名管道),消息队列.共享内存.UNIX域套接字(socket): 1种实现异步机制:信号: 1种实现互斥和同步:信号量: ①.管道(pipe) 管道是一种特殊的文件: 管道是文件:可对它使用文件IO的读写函数: 特殊的:管道是由内核实现的,在内存中文件,它不能使用类似fseek.lseek()的对文件指针的操作:管道是单向的(半双工): (1).无名管

Paramics插件编程进程间通讯

一.进程间通讯 进程间的通讯,包括数据的交换与共享是一项实用的技术,多应用在大型系统中,一个大型的系统往往由多个程序部件组成,部件的形式是多种多样的,可以是动态链接库(DLL).Activex组件或控件,也可以是独立运行的程序.因此,在系统运行时各相关程序部件必然需要进行大量频繁的数据交换操作.动态链接库(DLL)与其主调应用程序之间的数据交换是非常容易实现的,但在两个应用程序之间,或是动态链接库与其主调应用程序之外的其他应用程序进行数据交换,就需要使用进程间通讯(interprocess co

Android(IPC)进程间通讯1:详解Binder由来?

完整原文:http://tryenough.com/android-ipc1 Android开发的进程间通讯,整个Android的应用都依赖于binder做底层通信机制.而Linux中提供的进程间通讯方式并没有binder机制,那么android中为什么要单独创造这种通讯方式呢?带着这个问题,继续往下读. Linux中进程相关概念 Linux将系统内存划分成了 用户空间 和 内核空间 两部分: 用户空间 : 普通应用程序则运行在用户空间上,它们不能使用某些特定的系统功能,不能直接访问硬件,不能直

【进程间通讯与进程池】 -- 2019-08-11 18:46:25

原文: http://106.13.73.98/__/4/ 目录 一.队列 二.管道 三.进程间数据共享 四.进程池 进程间通讯:IPC(Inter-Process Communication) 一.队列: 队列:先进先出(First In First Out)简称 FIFO 栈:先进后出(First In Last Out)简称 FILO 1. multiprocessing.Queue模块 用于创建共享的进程队列,Queue是多进程安全的队列,可以实现对进程之间的数据传递,队列底层是使用管道

【进程间通讯与进程池】 -- 2019-08-16 18:12:52

原文: http://blog.gqylpy.com/gqy/230 " 目录 一.队列 二.管道 三.进程间数据共享 四.进程池 进程间通讯:IPC(Inter-Process Communication) 一.队列: 队列:先进先出(First In First Out)简称 FIFO 栈:先进后出(First In Last Out)简称 FILO 1. multiprocessing.Queue模块 用于创建共享的进程队列,Queue是多进程安全的队列,可以实现对进程之间的数据传递,队列

【进程间通讯与进程池】 &#223572;

原文: http://blog.gqylpy.com/gqy/230 " 目录 一.队列 二.管道 三.进程间数据共享 四.进程池 进程间通讯:IPC(Inter-Process Communication) 一.队列: 队列:先进先出(First In First Out)简称 FIFO 栈:先进后出(First In Last Out)简称 FILO 1. multiprocessing.Queue模块 用于创建共享的进程队列,Queue是多进程安全的队列,可以实现对进程之间的数据传递,队列