Linux进程通信

来源:互联网 发布:山海经知乎 编辑:程序博客网 时间:2024/04/30 22:58

一、进程通信

(一)、Linux进程间通信有以下几个版本:
1、UNIX进程间通信
2、基于system进程间通信
3、基于POSIX进程间通信
(二)、进程间通信方式
1、管道(pipe)与有名管道(FIFO)
2、信号(singal)
3、消息队列
4、共享内存
5、信号量
6、套接字(sockfd)
(三)、管道
特点:
1、单向,先进先出,尾部写,头部读
2、读完变删除
3、当管道数据已满或管道内无数据时,进程会阻塞
无名管道:父子进程之间的通信
有名管道:任意两个进程之间的通信
4、无名管道创建方式:
int pipe(int fields[2]);
此函数创建两个文件描述符:fields[0]、fields[1],第一个文件以只读方式打开,为读取端,将fields[0]的文件读入管道。第二个文件以只写方式打开,将管道内的文件写入fields[1];
注意点:

应该在fork之前先创建管道。如图释:


例子:

#include <unistd.h>#include <errno.h>#include <stdio.h>#include <stdlib.h>int main(){ int pipe_fd[2]; if(pipe(pipe_fd)<0) {  printf("pipe create error\n");  return -1; } else  printf("pipe create success\n"); close(pipe_fd[0]); close(pipe_fd[1]);}
如果是父进程给子进程发消息:
父进程:
先close(fd[0]);把读关掉,先往里写
子进程:
先close(fd[1]);
5、有名管道创建方式
int mkfifo(const char * pathname,mode_t mode);
pathname:FIFO文件路径    mode:该文件的权限
(四)、共享内存(最快的方式)
头文件:#include <sys/shm.h>

创建共享内存两步骤:
1、创建共享内存:shmget    开辟内存
int shmget(key_t key,int size,int shmflg);
key:两个键值:0/IPC_PRIVATE
如果成功,返回共享内存标识符,如果失败,返回-1
2、映射共享内存:shmat    程序共享虚拟地址
char shmat(int shmid,char *chmaddr,int flag);
shmid:内存标识符    flag:置0


一旦创建了一个FIFO,就可用open打开它,一般的文件访问函数(close、read、write等)都可用于FIFO

(五)、消息队列
头文件:#include <sys/msg.h>
可传送有格式的字节流
消息队列的创建
1、创建消息队列需要先申请键值
key_t ftok(char *pathname,char proj);
pathname:文件名    proj:随机取
成功返回键值
2、int msgget(int key_t,int msgflg);
key_t:键值    msgflag:IPC_CREATE
返回值:消息队列描述符
3、int msgsnd(int msqid,struct msgbuf *msgp,int msgsz,int msgflg);
msqid:消息队列描述符    
msgp:
struct msgbuf
{
    int type;    //不可变
    char buffer[1025];    //发的消息
};
msgsz:消息大小
msgflg:IPC_NOWAIT(不堵塞)
4、int msgrcv(int msqid,struct msgbuf *msggp,int msgsz,long msgty,int msgflg);
msqid:消息队列描述字
msgp:
struct msgbuf
{
    int type;    //不可变
    char buffer[1025];    //发的消息
};
msgsz:消息大小
msgty:第几个结构体
msgflg:IPC_NOWAIT
二、信号
(一)、信号处理方式:
1、忽略(其中SIGKILL和SIGSTOP不可忽略)
2、执行用户希望的动作
3、执行系统的默认动作
(二)、kill和raise
   #include <sys/types.h>
   #include <signal.h>
   int kill(pid_t pid, int signo)
   int raise(int signo)
kill的pid参数有四种不同的情况:
1、pid>0
   将信号发送给进程ID为pid的进程。
2、pid == 0
   将信号发送给同组的进程。
3、pid < 0
   将信号发送给其进程组ID等于pid绝对值的进程。
4、pid ==-1
 将信号发送给所有进程。
(三)、alarm
#include <signal.h>
unsigned int alarm(unsigned int seconds)
参数为经过多少秒发出警告
(四)、singal
例子:不可强制退出
#include <stdio.h>
#include <signal.h>


void func(int signal)
{
    if(signal == SIGINT)
    {
        printf("ctrl + c!\n");
    }
}


int main()
{
    signal(SIGINT,func);


    while(1)
    {
        printf("hello wrold!\n");
        pause();
    }
}
三、多线程编程
(一)、多线程特点
1、共享数据段,线程之间彼此切换所需的时间短,通信方式简单,使CPU系统更加有效,改善程序结构
(二)、线程的进程的区别
(三)、相关API:
头文件:#include <pthread.h>
1、创建线程
pthread_t id;
pthread_create(&id,NULL,print_msg,NULL);
可以重复创建,重复调用,谁先创建谁先执行,创建线程的程序一结束,所有子线程结束
2、线程等待函数
作用:主线程等待子线程结束了主线程才可结束
pthread_join(id,NULL);
3、pthread_exit(NULL)
在子线程中将该线程结束
4、第四个参数的使用


(四)、线程同步
保证线程同步的三种方法
1、互斥量(互斥锁)    2、信号灯    3、多量变量
过程:
全局变量中,先定义一把锁:pthread_mutex_t mutex;
主线程中初始化互斥锁:pthread_mutex_init(&mutex,NULL);
上锁:int pthread_mutex_lock(&mutex);
解锁:int pthread_mutex_unlock(&mutex);

例子:

#include <stdio.h>#include <pthread.h>int ticket = 10;pthread_mutex_t mutex;void sell_ticket(void * arg){    while(1)    {        pthread_mutex_lock(&mutex); if(ticket > 0) {     sleep(1); } else {     pthread_mutex_unlock(&mutex);     break; }  printf("Left tickets:%d\n",--ticket);  pthread_mutex_unlock(&mutex);    }}int main(){    pthread_t id1;    pthread_t id2;    pthread_t id3;       pthread_mutex_init(&mutex,NULL);    pthread_create(&id1,NULL,(void *)sell_ticket,NULL);    pthread_create(&id2,NULL,(void *)sell_ticket,NULL);    pthread_create(&id3,NULL,(void *)sell_ticket,NULL);    pthread_join(id1,NULL);    pthread_join(id2,NULL);    pthread_join(id3,NULL);    return 0;}


0 0