进程间通信学习总结

来源:互联网 发布:淘宝时间倒计时代码 编辑:程序博客网 时间:2024/04/30 23:43

        最近学习linux进程通信,发现通信方法太多且具体实现的函数各不相同。最近有些眉目特总结下。由于水平有限,错误之处请大家指出。

        管道和有名管道就不用说了,比较好理解。然后还有三种通信方式。分别是:消息队列,信号量(灯?),共享内存。问题就在这。这三种方式又分为两种标准:System V 和POSIX(可能还有别的标准)。而这两种标准的函数又不一样。初学时困扰了我很久。

      

先说System V消息队列主要有以下几个函数。
       #include    <sys/msg.h>
       int msgget(ket_t key, int oflag);
       int msgsnd(int msgid, const void *ptr, size_t length, int flag);

       ssize_t msgrcv(int msgid, void *ptr, size_t length, long type, int flag);
       int msgctl(int msqid, int cmd, struct msqid_ds *buff);
      

       msgget()不多说了,msgsnd()和msgrcv()的ptr是一个结构指针,该结构具有如下:

           #include    <sys/msg.h>
            struct msgbuf
               {
                     long int mtype;     /* message type, must be > 0 */
                     char mtext[];      /* message da
ta */
               };
       其中mtype为一长整型。可以根据mtype指定接收哪条消息。
      msgctl()的buf也是一个结构指针,该结构如下:
                #include    <bits/msgq.h>
                   struct msqid_ds
                     {
                         struct ipc_perm  msg_perm;  /* read-write perms: Section 3.3 */
                         struct msg      *msg_first; /* ptr to first message on queue */
                         struct msg      *msg_last;  /* ptr to last message on queue */
                         msglen_t        msg_cbytes; /* current #bytes on queue */
                         msgqnum_t       msg_qnum;   /* current #of message on queue */
                         msglen_t        msg_qbytes; /* max #of bytes allowed on queue */
                        pid_t           msg_lspid;  /* pid of last msgsnd() */
                        pid_t           msg_lrpid;  /* pid of last msgrcv() */
                        time_t          msg_stime;  /* time of last msgsnd() */
                        time_t          msg_rtime;  /* time of last msgrcv() */
                        time_t          msg_ctime;  /* time of last msgctl() */
                    };
   cmd可选到宏为IPC_STAT:取队列的msqid_ds结构放在buf所指向的结构中。需要buf。
                            IPC_SET:对队列相关结构成员赋值,包括msg_perm.uid,msg_perm.gid
                                            msg_perm.mode,msg_perm.uid
                            IPC_RMID:删除队列,并清除队列中所有消息。

使用时 一个进程用qid=msgget()创建消息队列,返回qid,msgrcv(),msgsed()根据qid就可以读写队列了。




然后是POSIX消息队列


#include    <mqueue.h>
typedef int mqd_t;
mqd_t mq_open(const char *name,int oflag);
mqd_t mq_open(const char *name, int oflag,/* mode_t mode, struct mq_attr *attr */);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name)
int mq_getattr(mqd_t mqdes, struct mq_attr *attr);
int mq_setattr(mqd_t mqdes, const struct mq_attr *attr, struct mq_attr *attr);

int mq_send(mqd_t mqdes, const char *ptr, size_t len, unsigned int prio);
ssize_t mq_receive(mqd_t mqdes, char *ptr, size_t len, unsigned int *priop);
int mq_notify(mqd_t mqdes, const struct sigevent *notification);



每个消息都有四个属性:
struct mq_attr
{
    long mq_flags;      /* message queue flag : 0, O_NONBLOCK */
    long mq_maxmsg;     /* max number of messages allowed on queue*/
    long mq_msgsize;    /* max size of a message (in bytes)*/
    long mq_curmsgs;    /* number of messages currently on queue */
};

mq_open()的oflag中包括O_CREAT标志,则必须提供 mode和 attr。mq_close关闭消息队列 mq_unlink删除消息队列。mq_getattr, mq_setattr分别为获得和设置属性,只能改mq_flags成员。




System V共享内存

#include<sys/shm.h>
int shmget(key_t key,size_t size,int flag);
int shmctl(int shm_id,int cmd,struct shmid_ds *buf);
void *shmat(int shm_id,const void *addr,int flag);
int shmdt(void *addr);

其中shmid_ds结构体定义如下:
  struct shmid_ds
     {
         struct ipc_perm shm_perm;
         size_t                  shm_segsz;
         pid_t                     shm_lpid;
         pid_t                     shm_cpid;
         shmatt_t              shm_nattch;
         time_t                  shm_attime;
         time_t                   shm_dtime;
         ....................
     }
这里我觉得有点奇怪,shmat()和shmdt()只能引入活脱离共享内存,但没删除共享内存函数。



POSIX共享内存


#include <sys/mman.h>
int shm_open(const char *name,int oflag,mode_t mode);
int shm_unlink(const char *name);
int ftruncate(int fd,off_t length);
int stat(const char *file_name,struct stat *buf);
void *mmap(void *addr,size_t length,int prot, int flags,int fd,off_t offset);
int munmap(void *addr,size_t length);


shm_open()和shm_unlink()打开和关闭一个共享内存区。打开后用ftrucate()改变共享内存区大小。mmap()将打开的共享区映射到当前进程空间,可以直接对这块内存区操作。munmap()相反。stat()可获得共享区信息。格式如下:
struct stat{
mode_t st_mode;
uid_t st_uid;
gid_t st_gid;
off_t st_size;
};



System V信号量


#include <sys/types.h>;
#include <sys/ipc.h>;
#include <sys/sem.h>;
key_t ftok(char *pathname,char proj);
int semget(key_t key,int nsems,int semflg);
int semctl(int semid,int semnum,int cmd,union semun arg);
int semop(int semid,struct sembuf *spos,int nspos);

struct sembuf {
short sem_num; 
  /*使用那一个信号 */
shortsem_op; 
    /* 进行什么操作 */
shortsem_flg; 
    /* 操作的标志 */
};

 

这个么大用过。就抄了点函数。其中ftok()用来产生key。所有System V IPC都用这个汉说生成key。但我测试时都不用ftok()。产生的key都一样但ID不一样,我觉得可以用ID来区分,还望高手指点。

 

 

 

POSIX 信号量

 

#include<semaphore>

sem_t *sem_open( const char *name,int folag);

sem_t *sem_open( const char *name,int folag,mode_t mode,unsigned int value);

int sem_close(sem_t *sem);

int sem_unlink(const char *name);

int sem_destroy(sem_t *sem);

int sem_init(sem_t *sem, int pshared, unsigned int value);

int sem_wait(sem_t *sem);

int sem_post(sem_t *sem);

int sem_trywait(sem_t *sem);

int sem_getvalue(sem_t *sem, int *sval);

 

这个比较简单也不写了(主要是吃饭时间到了,下午还有事)。