【初探】进程通信与线程同步

来源:互联网 发布:网络拒绝接入什么意思 编辑:程序博客网 时间:2024/05/17 01:46

  • 日期:20160608
  • 作者:i.sshe
  • https://github.com/isshe

进程通信与线程同步

1. 基本问题

  • 1.1 进程通信的方式有哪些,哪些是比较常用的?
  • 1.2 线程同步的机制有哪些?

2. 拓展问题

3. 基本问题解答

3.1 进程通信的方式有哪些,哪些是比较常用的?

  • 信号
    • 通信的信息只是一个信号值;
    • 信号是进程间通信机制中唯一的异步通信机制.
    • 信号的产生主要有两个来源:
      • 硬件来源: 按下键盘组合键, 某些硬件故障
      • 软件来源: 系统调用alarm(), kill(), raise(), settimer()等.
    • 不推荐使用signal()接口, 推荐使用sigacton();
    • 相关接口:
      • signal()
      • signaction()
    • 信号集处理函数:
      • int sigaddset(sigset_t *set, int signo);
        • 添加信号到信号集;
      • int sigemptyset(sigset_t set);
        • 初始化信号集为空;
      • int sigfillset(sigset_t set);
        • 将信号集初始化为包含所有已定义的信号.
      • int sigdelset(sigset_t set, int signo);
        • 从信号集中删除信号.
      • int sigmember(sigset_t set, int signo);
        • 判断signo是否是信号集的成员
      • int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
        • 设置,检查进程的信号屏蔽字.
      • int sigpending(sigset_t *set);
        • 查看阻塞的信号中有哪些正停留在待处理状态.
      • int sigsuspend(const sigset_t *sigmask);
        • 挂起, 直到信号集中的一个信号到达为止.和pause()类似.
  • 管道
    • 通常把一个进程的输出通过管道连接到另一个进程的输入;
    • 相关接口:
      • FILE *popen(const char *command, const char *open_mode);
        • 允许一个程序将另一个程序作为新进程来启动, 并可以给它传递数据或者接收数据;
        • 经常用来执行一些linux命令.
        • 使用的是文件流;
      • int pclose(FILE *stream_to_close);
        • 关闭popen打开的文件流;
      • int pipe(int file_descriptor[2]);
        • 使用的是文件描述符;
        • file_descriptor[0]:读;
        • file_descriptor[1]:写;
        • 数据基于先进先出原则;
          *注意:
      • 使用文件描述符时用底层的read()和write()来访问数据;
      • 使用文件流时用fread()和fwrite()访问数据;
  • I/O重定向
  • 信号量

    • 用于管理对资源的访问, 保护临界资源;
    • 定义: 它是一个特殊变量,只允许对它进行等待(wait)和发送信号(signal);
      • P(信号量变量):用于等待;(来源于荷兰语单词passeren(传递));
      • V(信号量变量):用于发送信号;(来源与荷兰语单词vrijgeven(给予或释放));
      • 例如:
        • P(sv),如果sv的值大于0,则减1;如果等于0,挂起;
        • V(sv),如果有其他进程因等待sv挂起,则让它恢复运行;如果没有,则给sv加1;
    • 伪码:


      • semaphore sv = 1;loop forever{    P(sv);    critical code section;    V(sv);    noncritical cose section;}
    • 图示:
      • 这里写图片描述
    • 相关接口:
      • int semget(key_t key, int num_sems, int sem_flags);
        • 创建一个新信号量或取得一个已有信号量的键;
      • int semop(int sem_id, struct sembuf *sem_ops, size_t num_sem_ops);
        • 改变信号量的值;
      • int semctl(int sem_id, int sem_num, int command, …)
        • 用来直接控制信号量信息;
        • 如果还有第4个参数, 则是一个union semun结构.
          union semun{    int val;    struct semid_ds *buf;    unsigned short *array;}
  • 共享内存

    • 用于在程序之间高效地共享数据;
    • 相关接口:
      • int shmget(key_t key, size_t size, int shmflg);
        • 获取一个共享内存标识符或创建一个共享内存对象。
      • void *shmat(int shmid, const void *shmaddr, int shmflg);
        • 把共享内存区对象映射到调用进程的地址空间。
      • int shmdt(const void *shmaddr);
        • 断开共享内存连接。
      • int shmctl(int shmid, int cmd, struct shmid_ds *buf);
        • 共享内存管理。
  • 信息队列

    • 在程序之间传递数据的一种简单方法;
    • 提供一种从一个进程向另一个进程发送一个数据块的方法.
    • 每个数据块都有类型,接收进程可以独立地接收含有不同类型值的数据块.
    • 相关接口:
      • int msgget(key_t key, int msgflg);
        • 获取一个消息队列标识符。(system v);
      • int msgctl(int msqid, int cmd, struct msqid_ds *buf);
        • 消息控制操作。在指定msqid上执行cmd指定的控制操作。
        • cmd有三选项:IPC_STAT, IPC_SET, IPC_RMID,
        • cmd linux特有选项:IPC_INFO, MSG_INFO, MSG_STAT;
      • int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
        • 添加消息到消息队列中;
      • ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
        • 从消息队列获取消息,msgtyp为0时获取消息队列中第一个消息。

3.2 线程同步的机制有哪些?

  • 临界区
    • 通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.
  • 互斥量(和二进制信号量类似)
    • 用来保护一段代码一次只能有一个线程执行.
    • 相关接口:
      • int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
      • int pthread_mutex_lock(pthread_mutex_t *mutex);
      • int pthread_mutex_unlock(pthread_mutex_t *mutex);
      • int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • 信号量
    • 允许多个线程同一时刻访问同一资源.[“多个”有限制!]
    • 信号量有:二进制信号量(只有0,1两种取值),计数信号量;
    • 一般用来保护一段代码,使其每次只能被一个执行线程执行(用二进制信号量实现);如果是是特定数量线程能执行,则用计数信号量;
    • 相关接口:
      • int sem_init(sem_t *sem, int pshared, unsigned int value);
        • 初始化由sem指向的信号量对象,设置它的共享选项;
      • int sem_wait(sem_t *sem);
        • 以原子操作的方式将信号量的值减一;
      • int sem_post(sem_t *sem);
        • 以原子操作的方式将信号量的值加一;
      • int sem_destroy(sem_t *sem)
        • 清理该信号量拥有的所有资源.如果企图清理的信号量正被一些线程等待, 则会收到一个错误.
  • 事件
    • 用来通知线程有一些事情已经发生,从而启动后继任务.

4. 拓展问题解答

5. 参考资料

  • 5.1 《linux就是这个范儿》
  • 5.2 《linux程序设计》

6. 相关代码

第二遍的时候补代码,必要时开新文

0 0