Linux-IPC

目录

 

1.Linux进程间通信方法

2. 管道

2.1 shell中的管道

2.2 无名管道 编程

2.2.1 关于fork函数

fork(函数)

2.2.2 无名管道代码

2.3 有名管道

SIGCHLD

描述

3. 消息队列

4. 信号量

5. 共享内存

6.线程

6.1 线程函数

互斥量的操作函数

读写锁

条件变量

自旋锁


1.Linux进程间通信方法

  1. 管道
  2. 有名管道
  3. 消息队列
  4. 信号量
  5. 共享内存

2. 管道

  1. 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
  2. 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  3. 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  4. 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。

2.1 shell中的管道

下面命令用创建了auxgrep管道|,筛选出进程中包含jk字符串的信息

ps - aux -aux 显示所有包含其他使用者的行程 

ps aux | grep jk

2.2 无名管道 编程

无名管道的特点是:使用其通信的进程必须有亲属关系,例如父子 兄弟进程

使用头文件:#include <unistd.h>

pipe编程

2.2.1 关于fork函数

fork(函数)

 UNIX及类UNIX(UNIX-like)系统中的分叉函数。返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。

fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。

#include <unistd.h>
#include <iostream>
using namespace std;
int main()
{
    pid_t pid;
    pid=fork();
    if(pid==0)
      cout<<"当前进程是子进程:pid="<<pid<<endl;
    else 
      cout<<"当前进程是父进程,返回所创建的子进程的pid="<<pid<<endl;
    while(1);
    return 0;
}

2.2.2 无名管道代码

这段代码需要注意一个问题,父子进程运行的先后顺序在不同设备上是不一定的,设计的代码应当不受其执行先后顺序的影响,但是下列代码是要先执行父进程,在执行子进程才行,后续还可以改进!!!

#include <unistd.h>
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
char str[]="hello world,my pipe!";
int main()
{
  //创建管道,pid[0] [1] 分别为读和写
   int fd[2];//定义两个文件描述符
   int result=pipe(fd);
   int *write_fd=&fd[1],*read_fd=&fd[0];//绑定描述副
   
   int nbytes;
   char read_buff[100]={""};
   if(result==-1)
     cout<<"fail to create pipe!"<<endl;
   pid_t pid;//创建进程号
   result=-1;
   pid=fork();//创建两个进程
   if(pid==-1)
     cout<<"fail to fork!"<<endl;
   if(0==pid)//执行子进程代码,接受
   {
     close(*write_fd);
      nbytes=read(*read_fd,read_buff,sizeof(read_buff));
      printf("the parent read %d bytes:%s",nbytes,read_buff);  
      return 0;
   }
   else//父进程  发送
   {  
     close(*read_fd);
     result=write(*write_fd,str,strlen(str));
     cout<<"the child send the string "<<str<<endl; 
   }
   
   while(1);
   return 0;
}

2.3 有名管道

SIGCHLD

SIGCHLD属于unix以及类unix系统的一种信号

产生原因 siginfo_t代码值

1,子进程已终止 CLD_EXITED

2,子进程异常终止(无core) CLD_KILLED

3,子进程异常终止(有core) CLD_DUMPED

4,被跟踪子进程以陷入 CLD_TRAPPED

5,子进程已停止 CLD_STOPED

5,停止的子进程已经继续 CLD_CONTINUED

描述

在一个进程终止或者停止时,将SIGCHLD信号发送给其父进程。按系统默认将忽略此信号。如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。信号的捕捉函数中通常调用wait函数以取得进程ID和其终止状态。

代码参考(待测试)http://blog.chinaunix.net/uid-20498361-id-1940238.html

3. 消息队列

4. 信号量

5. 共享内存

https://www.cnblogs.com/fangshenghui/p/4039720.html

6.线程

多线程总结

线程同步的方式有多种:

  • pthread_join的等待执行结束
  • 互斥量
  • 条件量
  • 自旋锁
  • 读写锁

6.1 线程函数

#include <pthread.h>
int pthread_create(pthread_t * tidp, const pthread_attr_t *attr, void *(*start_rtn) (void *), void *arg);
  • 第一个参数为指向线程标识符指针
  • 第二个参数用来设置线程属性,默认为NULL
  • 第三个参数是线程运行函数的起始地址。
  • 最后一个参数是运行函数的参数,即线程运行函数的输入参数

成功返回0,错误返回错误编号

#include <pthread.h>
void pthread_exit(void *rval_ptr);
    // 线程终止
//pthread_exit用于强制退出一个线程(非执行完毕退出),一般用于线程内部。

线程可以通过以下三种方式退出,在不终止整个进程的情况下停止它的控制流:

  • 线程只是从启动过程中退出,返回值是线程的退出码
  • 线程可以被同一进程中的其他线程取消
  • 线程调用pthread_exit
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
    // 返回:成功返回0,出错返回错误代码
//thread: 线程标识符,即线程ID,标识唯一线程。retval: 用户定义的指针,用来存储被等待线程的返回值。

用于等待线程结束,并用rval_ptr获取线程结束的返回值

互斥量的操作函数

#include <pthread.h>
//互斥量初始化
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
//摧毁互斥量,互斥量使用完毕再调用!!
int pthread_mutex_destroy(pthread_mutex_t *mutex);
    // 两个函数返回值,成功返回0,否则返回错误码
//加锁
int pthread_mutex_lock(pthread_mutex_t *mutex);//如果目标互斥锁已经被加锁,则pthread_mutex_lock则被阻塞,直到该互斥锁占有者把它给解锁。
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
    // 成功返回0,否则返回错误码

读写锁

读写锁和互斥体类似,不过读写锁有更高的并行性,互斥体要么是锁住状态,要么是不加锁状态,而且一次只有一个线程可以对其加锁。而读写锁可以有3个状态,读模式下锁住状态,写模式下锁住状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是多个线程可以同时占用读模式的读写锁。读写锁适合对数据结构读的次数远大于写的情况

当读写锁是写加锁状态时,在这个锁被解锁之前,所有试图对这个锁加锁的线程都会被阻塞。当读写锁是读加锁状态时,所有试图以读模式对它进行加锁的线程都可以得到访问权,但是任何希望以写模式对此锁进行加锁的线程都会阻塞,直到所有的线程释放它们的读锁为止。

当前状态 可执行的操作 不可执行的操作
读加锁 所有试图读加锁的操作可执行 写加锁操作不可执行
写加锁 对齐加锁的线程可以获得访问权 其他试图对其加锁的线程都被阻塞
不加锁 ALL ALL

条件变量

条件变量是线程可用的一种同步机制,条件变量给多个线程提供了一个回合的场所,条件变量和互斥量一起使用,允许线程以无竞争的方式等待特定的条件发生。条件变量本事是由互斥体保护的,线程在改变条件状态之前必须首先锁住互斥量,其他线程在获取互斥量之前就不会觉察到这种变化,因为互斥量必须锁定之后才改变条件。

#include<pthread.h>
pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
pthread_cond_destroy(pthread_cont_t *cond);
    // 成功返回0,否则返回错误码
  使用条件变量前调用pthread_cond_init初始化,使用完毕后调用pthread_cond_destroy做清理工作。除非需要创建一个具有非默认属性的条件变量,否则pthread_cond_init函数的attr参数可以设置为NULL。

#include<pthread.h>
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
    // 成功返回0,否则返回错误码
  
条件变量
传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住互斥量传给函数,函数然后自动把调用线程放到等待条件的线程列表上,对互斥量解锁。这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait函数返回时,互斥量再次被锁住。

  pthread_cond_broadcast用广播的形式唤醒所有等待条件变量的线程。pthread_cond_signal用于唤醒一个等待条件变量的线程,至于哪个线程被唤醒,取决于线程的优先级和调度机制。有时候需要唤醒一个指定的线程,但pthread没有对该需要提供解决方法。可以间接实现该需求:定义一个能够唯一表示目标线程的全局变量,在唤醒等待条件变量的线程前先设置该变量为目标线程,然后以广播形式唤醒所有等待条件变量的线程,这些线程被唤醒后都检查改变量是否是自己,如果是就开始执行后续代码,否则继续等待。

自旋锁

  自旋锁和互斥量类似,但它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)状态,自旋锁可用于下面的情况:锁被持有的时间短,并且线程不希望再重新调度上花费太多的成本。自旋锁通常作为底层原语用于实现其他类型的锁。根据他们所基于的系统架构,可以通过使用测试并设置指令有效地实现。当然这里说的有效也还是会导致CPU资源的浪费:当线程自旋锁变为可用时,CPU不能做其他任何事情,这也是自旋锁只能够被只有一小段时间的原因。

#include <pthread.h>
int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
int pthread_spin_destroy(pthread_spinlock_t *lock);
  pshared参数表示进程共享属性,表明自旋锁是如何获取的,如果它设为PTHREAD_PROCESS_SHARED,则自旋锁能被可以访问锁底层内存的线程所获取,即使那些线程属于不同的进程。否则pshared参数设为PTHREAD_PROCESS_PROVATE,自旋锁就只能被初始化该锁的进程内部的线程访问到。

#include <pthread.h>
int pthread_spin_lock(pthread_spinlock_t *lock);
int pthread_spin_trylock(pthread_spinlock_t *lock);
int pthread_spin_unlock(pthread_spinlock_t *lock);

  如果自旋锁当前在解锁状态,pthread_spin_lock函数不要自旋就可以对它加锁,试图对没有加锁的自旋锁进行解锁,结果是未定义的。需要注意,不要在持有自旋锁情况下可能会进入休眠状态的函数,如果调用了这些函数,会浪费CPU资源,其他线程需要获取自旋锁需要等待的时间更长了。

https://www.cnblogs.com/wujing-hubei/p/5222013.html

https://www.cnblogs.com/luoxn28/p/6087649.html

https://www.cnblogs.com/yangang92/p/5679641.html

猜你喜欢

转载自blog.csdn.net/weixin_37058227/article/details/83184816
今日推荐