进程间通信(Linux)(C)

13 篇文章 0 订阅

无名管道

创建:
		int pipe(int fd[2]);
		功能:在内核中创建处理一个无名管道,并产生两个文件描述符(fd[0]为读,fd[1]为写)
		返回值:成功0,失败-1
		fd:产生的文件描述符

读:读过的数据会消失
		写端存在时:读取数据会返回实际读到的字节数,若没有数据那么read会阻塞等待
		写端不存在时:读取数据的话会返回实际读到的字节数,若没有数据那么read会返回0

写:
		读端存在时:正常写入数据,如果管道空间大于要写的数据大小。那么可以把数据全部写入;若管道大小小于读入的数据,只会写入一部分并阻塞,当数据被读走后再写入
		读端不存在时:写入会导致管道破裂(SIGPIPE)程序直接结束

有名管道

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:创建一个以 FIFO 的文件存在于文件系统中,并且其打开方式与打开一个普通文件是一样的
返回值:成功0,失败非0(可以使用errno来判断错误信息)

信号通信

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
功能:调用kill的进程可以向任意进行发送信号
返回值:成功0,失败-1
pid:要接收的进程ID
sig:信号

#include <signal.h>
int raise(int sig);
功能:给此进程发送信号
返回值:成功0,失败-1
sig:信号

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:启动一个计时器,开始计时,计数完成结束程序
返回值:返回0,返回前一个闹钟的剩余时间
seconds:秒数,若为0表示取消闹钟

#include <unistd.h>
int pause(void);
功能:使进程挂起,当有信号时,进程继续运行
返回值:成功返回正数,失败为-1


#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
//函数原型
void (*signal(int signum, void (*fun)(int)))(int)
功能:捕获一个规定的信号,选择不同的处理方式
返回值:成功信号处理函数的地址,失败
signum:某个信号
handler:信号处理函数

IPC对象

#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *pathname, int proj_id);
功能:生成一个key值,创建IPC对象时不冲突。
返回值:成功为key值,失败-1
pathname:文件路径名
proj_id:任意值
(key的生成需要一个文件的inode节点号和proj_id进行组合运算)

共享内存(shm)(高效)(类似字符串缓冲区空间)

ipcs:查看共享内存段
ipcrm -m 内存端id:删除此内存段
多个进程可以访问同一内存空间,而每个进程都是独立的空间,那么共享内存只能在内核中。
内核会映射这个空间到用户空间。需要同步互斥机制。(当写入时,会覆盖原有的所有内容)

#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
功能:打开或创建一个共享内存对象
返回值:成功id号,失败-1
key:唯一标识符(ftok的值,如果要变成私有对象使用IPC_PRIVATE或0)
size:要创建的共享内存空间大小
shmflg:打开权限

#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:把共享内存的内核空间映射到用户空间
返回值:成功返回地址,失败(void*)-1
shmid:内存idhao
shmaddr:指定用户空间的地址(默认NULL)
shmflg:读写权限(访问)0可读写

int shmdt(const void *shmaddr);
功能:取消映射
返回值:成功0,失败-1
shmaddr:映射地址

#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:共享内存对象的控制操作
返回值:成功0,失败-1
shmid:共享内存段id
cmd:控制操作
buf:获取相关信息结构体

struct shmid_ds 
{
           		struct ipc_perm shm_perm;    /* Ownership and permissions */
           		size_t          shm_segsz;   /* Size of segment (bytes) */
           		time_t          shm_atime;   /* Last attach time */
           		time_t          shm_dtime;   /* Last detach time */
          		time_t          shm_ctime;   /* Last change time */
           		pid_t           shm_cpid;    /* PID of creator */
           		pid_t           shm_lpid;    /* PID of last shmat(2)/shmdt(2) */
           		shmatt_t        shm_nattch;  /* No. of current attaches */
           		...
       	};
struct ipc_perm 
{
           		key_t          __key;    /* Key supplied to shmget(2) */
           		uid_t          uid;      /* Effective UID of owner */
           		gid_t          gid;      /* Effective GID of owner */
           		uid_t          cuid;     /* Effective UID of creator */
           		gid_t          cgid;     /* Effective GID of creator */
           		unsigned short mode;     /* Permissions + SHM_DEST and SHM_LOCKED flags */
           		unsigned short __seq;    /* Sequence number */
       	};
消息队列(msg)
按照类型来选择是否接收消息,也是在内核中有一片空间交换信息,
但不需要映射

struct msgbuf //消息结构体
{
           		long mtype;       /* message type, must be > 0 */
           		char mtext[1];    /* message data */
};


#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg);
功能:打开或创建一个消息队列对象
返回值:成功队列id,失败-1
key:唯一标识符(ftok的值,如果要变成私有对象使用IPC_PRIVATE或0)
msgflg:打开权限

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
功能:往队列中发送某个类型的消息
返回值:成功为0,失败-1
msqid:消息队列id号
msgp:消息结构体
msgsz:消息结构体大小
msgflg:IPC_NOWAIT不等函数执行完成就返回(不阻塞),0函数执行完返回(阻塞)

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
功能:从消息队列中提取关心的消息
返回值:成功0,失败-1
msqid:消息队列id号
msgp:消息结构体
msgsz:消息结构体大小
msgtyp:关心的消息类型
msgflg:IPC_NOWAIT不等函数执行完成就返回(不阻塞),0函数执行完返回(阻塞)

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
功能:共享内存对象的控制操作
返回值:成功0,失败-1
msqmid:共享内存段id
cmd:控制操作
buf:获取相关信息结构体
信号灯集(sem)信号量的集合
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
int semget(key_t key, int nsems, int semflg);
功能:创建或打开一个信号灯集合对象
返回值:成功信号灯集id,失败-1
key:唯一标识符(ftok的值,如果要变成私有对象使用IPC_PRIVATE或0)
nsems:信号灯种类个数
semflg:打开权限

int semctl(int semid, int semnum, int cmd, ...);
功能:对信号灯集进行控制操作,设置内容、删除等
返回值:成功0,失败-1
semid:信号灯集id
semnum:信号灯编号(从0开始)
cmd:控制指令STEVAL(设置信号灯值)、GETVAL(获取信号灯的值)

int semop(int semid, struct sembuf *sops, size_t nsops);
功能:实现信号灯的申请和释放
返回值:成功0,失败-1
semid:信号灯集id
sops:
struct sembuf
{
	unsigned short sem_num;  /* semaphore number */
       		short          sem_op;   /* semaphore operation (1释放资源,-1申请)*/
       		short          sem_flg;  /* operation flags (0阻塞,IPC_NOWAIT不阻塞)*/
}
nsops:操作的信号量(此类信号量,此类资源)个数

部分代码示例

//无名管道
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{ 
    int fd[2];
    int ret = pipe(fd);
    if(ret<0)
    {
        perror("pipe");
        return -1;
    }
    printf("%d--->%d\n",fd[0],fd[1]);
    char buf[1];
    int count=0;
    while(1)
    {
        write(fd[1],buf,sizeof(buf));
        printf("%db\n",count++);
    }
    return 0;
} 
//有名管道
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>

int main(int argc, char *argv[])
{ 
    int ret = mkfifo("./Newfifo",0777);
    if(ret<0)
    {
        if(errno!=EEXIST)
        {
            return -1;
        }
    }
    int fd = open("./Newfifo",O_RDWR);
    char buf[64];
    while(1)
    {
        read(fd,buf,sizeof(buf));
        printf("%s",buf);
        memset(buf,0,sizeof(buf));
    }
    return 0;
} 
//共享内存
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
int main(int argc, char *argv[])
{ 
    key_t key = ftok(".",'a');



    int shmid = shmget(key,512,IPC_CREAT | 0666 |IPC_EXCL);
    if(shmid<0)
    {
        if(errno==EEXIST)
        {
            shmid = shmget(key,512,0666);
        }
        else
        {
            perror("shmget");
            return -1;
        }
    }
    printf("shmid=%d\n",shmid);



    char *shmaddr = (char*)shmat(shmid,NULL,0);
    /*if(shmaddr==-1)
    {
        perror("shmat");
        return -1;
    }*/
    printf("shmaddr=%p\n",shmaddr);
    fgets(shmaddr,64,stdin);
    printf("%s",shmaddr);



    int ret = shmdt(shmaddr);
    if(ret==-1)
    {
        perror("shmdt");
        return -1;
    }



    struct shmid_ds buf;
    int ret01 = shmctl(shmid,IPC_STAT,&buf);
    if(ret01==-1)
    {
        perror("shmctl01");
        return -1;
    }
    printf("shm_pid=%d\n",buf.shm_cpid);
    int ret02 = shmctl(shmid,IPC_RMID,NULL);
    if(ret02==-1)
    {
        perror("shmctl02");
        return -1;
    }
    return 0;
} 
//消息队列
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <unistd.h>
#include <errno.h>
struct msgbuf
{
    long mtype;
    char buf[64];
};
int main(int argc, char *argv[])
{ 
    int key = ftok(".",96);
    int msgid = msgget(key,IPC_CREAT | 0666 | IPC_EXCL);
    if(msgid<0)
    {
        if(errno==EEXIST)
        {
            msgid = msgget(key,0666);
        }
    }

    pid_t pid = fork();
    if(pid<0)
    {
        perror("fork");
        goto DestroyMsg;
    }
    else if(pid==0)
    {
        while(1)
        {
            struct msgbuf msgbuf_copy100;
            msgrcv(msgid,&msgbuf_copy100,sizeof(msgbuf_copy100),100,0);
            printf("child copy:%s\n",msgbuf_copy100.buf);
        }
    }
    else
    {
        struct msgbuf msgbuf100;
        msgbuf100.mtype=100;
        while(1)
        {
            fgets(msgbuf100.buf,sizeof(msgbuf100.buf),stdin);
            msgsnd(msgid,&msgbuf100,sizeof(msgbuf100),0);
        }
    }

DestroyMsg:
    msgctl(msgid,IPC_RMID,NULL);
    return 0;
} 
//信号量集
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <errno.h>
#include <unistd.h>
int semset(int semid,int *a,int n)
{
    for(int i=0;i<n;i++)
    {
        semctl(semid,a[i],SETVAL,a[i]);
    }
}
int sem_ops(int semid, int num, int op)
{
	struct sembuf buf;
	buf.sem_num = num;
	buf.sem_op = op;
	buf.sem_flg = 0;
	int ret = semop(semid, &buf, 1);
	if(ret < 0){
		perror("semop");
		return -1;
	}
	return 0;
}
int main(int argc, char *argv[])
{ 
    int key = ftok(".",'a');
    int semid = semget(key,2,IPC_CREAT | 0666 | IPC_EXCL);
    if(semid<0)
    {
        if(errno==EEXIST)
        {
            semid = semget(key,2,0666);
        }
        return -1;
    }

    int a[2]={0,1};
    semset(semid,a,2);
    pid_t pid = fork();
    if(pid<0)
    {
        perror("fork");
        return -1;
    }
    else if(pid==0)
    {
        while(1)
        {
            sem_ops(semid,0,-1);
            printf("Im child\n");
            sleep(1);
            sem_ops(semid,1,1);
        }
    }
    else
    {
        while(1)
        {
            sem_ops(semid,1,-1);
            printf("Im parent\n");
            sleep(1);
            sem_ops(semid,0,1);
        }
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值