c语言基础(十四)

消息队列

消息队列:默认发送端将信息放在前一个信息的后面,接收消息端可以指定接受哪一个消息。
1、msgget:创建和打开一个消息队列
int msgget(key_t key, int msgflg)
键值,这个键值就可以创建不同进程的消息对列。
参数1:键值;参数2:权限有关
ftok获得特定的键值。
key_t ftok(const char *pathname, int proj_id);
参数1:路径;参数2:至少是一个char的子符(非零)
2、msgsnd发送消息到消息队列
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
参数1:消息队列id;参数2:消息发送的信息结构体;参数3:大小(); 参数4:阻塞(0)或非阻塞(IPC_NOWAIT)
struct msgbuf
{
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
}
3、msgrcv 接受消息从消息队列
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
int msgflg);
有用的信息将来会放在msgp这个结构体的元素(数组)里。
msgflag 也是阻塞读取,意思就是有有消息就一直读
msgtyp,选择0,就是默认先读取第一个消息。
4、消息队列是在内核中维护的,用完之后,自己清理
msgctl
参数1:qid;参数2:IPC_RMID;参数:NULL(不关心详细的队列特性)

    题目:进程A 和 进程B,通过共享内存进行通信。
    PS:shmget注意是创建还是打开(共享内存)
//完成了发送端的程序
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define SIZE 200

struct msgbuf
{
        //消息的一个类型(>0)
        long mtype;
        //真实的消息
        char mtext[SIZE];
}; 

int main(void)
{
        key_t key = ftok(".", 'a');

        struct msgbuf msg = {0};
        struct msgbuf msg1 = {123, "computer"};

        int ret = -1;

        if (key < 0)
        {
                perror("ftok");

                exit(0);
        }
        else
        {
                printf("创建键值成功.\n");
        }

        //创建和打开一个消息队列
        int qid = msgget(key, IPC_CREAT | 0666);

        if (qid < 0)
        {
                perror("msgget");

                exit(0);
        }

        printf("打开了一个消息队列qid = %d.\n", qid);

        while (1)
        {
                //填充结构体
                msg.mtype = getpid();
                printf("输入消息:\n");
                fgets(msg.mtext, SIZE, stdin);
                //添加消息到消息队列,进行排队
                ret = msgsnd(qid, &msg1, SIZE, 0);
                if (ret < 0)
                {
                        perror("msgsnd1");

                        exit(0);
                }

                ret = msgsnd(qid, &msg, SIZE, 0);
                if (ret < 0)
                {
                        perror("msgsnd2");

                        exit(0);
                }
                //结束我们进程
                if (strncmp(msg.mtext, "quit", 4) == 0)
                        break;

        }




        return 0;
}

共享内存

共享内存:从真实的物理空间找一段内存,映射到我们的虚拟内存,在不同进程间的映射内存都以为这段内存是自己的,这就牵扯到同步。
1、从物理地址得到确定大小的内存
int shmget(key_t key, size_t size, int shmflg);
参数1:特殊键值 参数2:获取内存大小 3:内存的权限
PS:ipcs -m 专门可以查看共享内存的详细信息。
2、删除共享内存
shmctl
3、建立共享
void *shmat(int shmid, const void *shmaddr, int shmflg);
参数2:shmaddr == NULL,表示操作OS自动非配一个未使用而且安全的地址。
参数3shmflag:选则IPC_RDONLY只读模式,猜测选0是可读可写?
4、断开共享内存和所处进程之间的映射关系
int shmdt(const void *shmaddr);
参数:里面放的是,所处进程中映射过去的有效、合法、未使用地址


#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>


#define SIZE 2048

int main(void)
{
#if 1
        int shmid = 0;
        char *ptr = NULL;
        char flag[] = "i am a flag!";
        char buf[1024] = {0};

        pid_t pid;

        //创建共享内存
        shmid = shmget(IPC_PRIVATE, SIZE, 0666);

        if (shmid < 0)
        {
                perror("shmget");

                exit(0);
        }
        else
        {
                printf("创建申请的shm_memory:%d.\n", shmid);
        }
        //查看共享内存使用情况
//      system("ipcs -m");

        //创建进程
        pid = fork();

        if (pid < 0)
        {
                perror("fork");

                exit(0);
        }

        if (pid == 0)
        {
                // 子进程
                //映射内存
                ptr = shmat(shmid, NULL, 0);
                if (ptr == (void *)-1)
                {
                        perror("子进程shmat");
                        exit(0);
                }
                else
                {
                        printf("子进程映射的地址:%p.\n", ptr);
                }
                //读父进程的flag是否写入
                while (strncmp(ptr, flag, strlen(flag)))
                {
                        printf("子进程等有效数据\n");
                        sleep(5);
                }
                //读取父进程有效数据
//              strcpy(buf, ptr+strlen(flag));
//              printf("子进程得到有效数据[%s].\n", buf);
                struct infor
                {
                        char name[20];
                        int age;
                        int money;
                }s = {0};
                //接受结构体信息
                s = *((struct infor *)(ptr+strlen(flag)));
                printf("名字:%s, 年龄:%d, 存款:%d.\n", s.name, s.age, s.money);

                //子进程分离共享内存
                if (shmdt(ptr) < 0)
                {
                        perror("子进程ptr");
                        exit(0);
                }
                else
                        printf("子进程分离OK!\n");
//              system("ipcs -m");
                //删除共享内存
                if (shmctl(shmid, IPC_RMID, NULL) < 0)
                {
                        perror("子进程删除内存错误\n");
                        exit(0);
                }

                printf("子进程删除成功\n");

        }

        if (pid > 0)
        {
                // 父进程
                //映射内存
                ptr = shmat(shmid, NULL, 0);
                if (ptr == (void *)-1)
                {
                        perror("父进程shmat");
                        exit(0);
                }
                else
                {
                        printf("父进程映射的地址:%p.\n", ptr);
                }

                printf("父进程写东西:\n");
                //写正式内容
//              fgets(buf, SIZE, stdin);
                struct infor
                {
                        char name[20];
                        int age;
                        int money;
                }s = {"小丽", 16,  500000000};                
//              strncpy(ptr+strlen(flag), buf, strlen(buf));
                memcpy((struct infor*)(ptr+strlen(flag)), &s, sizeof(s));
                strncpy(ptr, flag, strlen(flag));
                //父进程分离共享内存
                if (shmdt(ptr) < 0)
                {
                        perror("父进程ptr");
                        exit(0);
                }
                else
                        printf("父进程分离OK!\n");
//              system("ipcs -m");
                //父进程等待子进程结束
                waitpid(pid, NULL, 0);

                printf("所犯的罪过一切结束了\n");             
        }

#endif  
/*  
        shmctl(5570615, IPC_RMID, NULL);
        shmctl(5603388, IPC_RMID, NULL);
        shmctl(5636157, IPC_RMID, NULL);

        system("ipcs -m");
*/      
//      shmctl(shmid, IPC_RMID, NULL);
        return 0;
}

信号

信号:是一种异步的通信方式,通信内容有限制。
信号:都是事先编好的一系列int数据
信号产生方式:
(1)硬件产生
(2)满足某种软件需求
(3)硬件异常发生信号
(4)kill -9
信号的处理方式:
给谁发的,谁处理
(1)默认处理
(2)捕获处理 (信号绑定了一个函数)
(3)忽略处理
常见的信号:(路径:/usr/include/bits/signum.h)
(1)SIGINT 2 就是平时用到的ctrl+c
(2)SIGABRT 6 程序异常终止
(3)SIGKILL 9 杀死一个进程(终极方法)
(4)SIGSEGV 11 无效访问内存
(5)SIGALRM 14 闹钟信号
(6)SIGCHLD 17 子进程结束时发送的信号
(7)SIGSTOP 19 杀死(暂停)一个进程ctrl+\
1、安装信号函数
raise发送一个信号给当前进程

#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

int main(void)
{
        pid_t pid;

        int ret = -1;

        pid = fork();

        if (pid < 0)
        {
                perror("fork");
                exit(0);
        }       

        if (pid == 0)
        {
                sleep(1);
                //子进程
                printf("子进程等待别的信号唤醒自己pid = %d:\n", getpid());
                raise(SIGSTOP);
                printf("子进程醒了.\n");
                exit(0);
        }

        if (pid > 0)
        {
                // 父进程
//              sleep(3);
                if (waitpid(pid, NULL, WNOHANG) == 0)
                {
                        //
                        if ((ret = kill(pid, SIGCONT)) == 0)
                        {
                                printf("父进程杀了子进程pid = %d.\n", pid);
                        }
                }

                waitpid(pid, NULL, 0);

                printf("一切结束.\n");
        }





        //一个进程发两个信号 
//      while (1);

/*
//      int i = 4 / 0;
        int i;
        printf("i = %d.\n", i);

        while (1);
*/



        return 0;
}

猜你喜欢

转载自blog.csdn.net/linzetao233/article/details/80227401
今日推荐