进程间通讯与同步的实现

来源:互联网 发布:软件商务网 编辑:程序博客网 时间:2024/05/22 11:30

进程通讯

  • 内存共享
    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 100int 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

1 0
原创粉丝点击