消息队列 与 信号 与 信号量

1.消息传递方式

发送消息

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
// //       int msgget(key_t key, int msgflg);
// //        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

// //       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
// //                      int msgflg);
struct msgbuf // 创建一个msgbuf 用来存read读取到的信息
{
	long mtype;		 // 消息类型,必须大于 0
	char mtext[256]; // 消息数据
};

int main()
{
	struct msgbuf readbuf;
	key_t key;
	key = ftok(".", 'm');
	int msgId = msgget(key, IPC_CREAT | 0777);
	if (msgId == -1)
	{
		printf("creat failed\n");
	}
	memset(&readbuf, 0, sizeof(struct msgbuf));
	// 具有阻塞机制 如果没有读到就一直阻塞
	// 2 指向消息缓冲区的指针,用于存储接收到的消息。
	// 3 消息缓冲区的大小,必须大于等于接收到的消息的大小
	// 4消息类型
	// 5与接收操作相关的标志。通常设置为 0 即可
	msgrcv(msgId, &readbuf, sizeof(readbuf.mtext), 888, 0);
	printf("read from que %s\n", readbuf.mtext);

	struct msgbuf sendbuf = {988, "this is from the get"};
	msgsnd(msgId, &sendbuf, strlen(sendbuf.mtext), 0);
	msgctl(msgId, IPC_RMID, NULL);

	
	return 0;
}

消息接收方式

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
//       int msgget(key_t key, int msgflg);
//        int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

//       ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
//                      int msgflg);
struct msgbuf
{

	long mtype;		 /* message type, must be > 0 */
	char mtext[256]; /* message data */
};

int main()
{
	// 1.huoqu
	struct msgbuf sendBuf = {888, "this is message from quen"};
	struct msgbuf readBuf;

	memset(&readBuf, 0, sizeof(struct msgbuf));
	key_t key;
	key = ftok(".", 'm');
	printf("key=%x\n", key);

	int msgId = msgget(key, IPC_CREAT | 0777);

	if (msgId == -1)
	{
		printf("get que failuer\n");
	}

	msgsnd(msgId, &sendBuf, strlen(sendBuf.mtext), 0);
	printf("send over\n");

	msgrcv(msgId, &readBuf, sizeof(readBuf.mtext), 988, 0);
	printf("reaturn from get:%s\n", readBuf.mtext);

	msgctl(msgId, IPC_RMID, NULL);

	return 0;
}

消息队列特性 : 不会销毁队列

 2.共享内存

创建 shmget -> 映射shmat -> 数据 -> 空间释放shmdt-> 干掉shmctl

shmget  创建共享内存 返回一个标识符

shmat 其中的第一个参数 shmid 代表需要映射的共享内存段的唯一标识符,第二个参数为 NULL,表示由系统自动选择地址进行映射,第三个参数为 0,表示不需要使用额外的选项。通过 shmat 函数,进程可以访问共享内存段中的数据,也可以修改这些数据。

shmdt 解除共享内存段与进程地址空间的映射。它使用了 shmdt 函数,其中的参数 shmaddr 代表需要解除映射的共享内存段的起始地址。调用 shmdt 函数后,该进程将无法再使用该共享内存段中的数据,也无法修改它。shmdt 函数执行成功后,共享内存段并未被销毁,只是与进程的地址空间解除了映射关系。

查看操作系统内共享内存 : ipcs -m

删除共享内存操作 ipcrm -m <序列号>

弊端 :无法控制哪个先写后写  需要用信号量操作

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
// int shmget(key_t key, size_t size, int shmflg);
int main()
{
	int shmid;
	char *shmaddr;

	key_t key;
	key = ftok(".", 1);

	shmid = shmget(key, 1024 * 4, IPC_CREAT | 0666);
	if (shmid == -1)
	{
		printf("Error no creat");
		exit(1);
	}

	shmaddr = shmat(shmid, 0, 0);
	printf("shared ok");
	strcpy(shmaddr,"chenlicken");
	sleep(5);
	shmdt(shmaddr);
	shmctl(shmid,IPC_RMID,0);
	printf("quit\n");
	return 0;
}

 共享内存写入

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

// int shmget(key_t key, size_t size, int shmflg);

int main()
{
	int shmid;
	char *shmaddr;

	key_t key;
	key = ftok(".", 1);

	shmid = shmget(key, 1024 * 4, 0); // 获取这个地址
	if (shmid == -1)
	{
		printf("Error no creat");
		exit(1);
	}
	shmaddr = shmat(shmid, 0, 0);
	printf("shared ok");
	printf("data: %s\n", shmaddr);
	shmdt(shmaddr);
	shmctl(shmid, IPC_RMID, 0);
	printf("quit\n");
	return 0;
}

共享内存的读取 

3.信号 signal 重点

捕显信号,需要告诉内核,用户希望如何处理某一种信号,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。·

系统默认动作,对于每个信号来说,系统都对应由默认的处理动作,当发生了该信号,系统会自动执行。不过,对系统来说,大部分的处理方式都比较粗暴,就是直接杀死该进程。

键盘按下ctrl c 没办法干掉我

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

void handler(int signum){

    printf("get the signal: %d\n", signum);
    printf("never quit\n");


}
int main(){

    signal(SIGINT,handler);
    while (1);

    return 0;
}

Ctrl + z即可终止

获取signal 信号

#include <signal.h>
#include <stdio.h>

//       typedef void (*sighandler_t)(int);

//       sighandler_t signal(int signum, sighandler_t handler);

void handler(int signum)
{
	printf("get signum=%d\n",signum);
	switch(signum){
		case 2:
			printf("SIGINT\n");
			break;
		case 9:
			printf("SIGKILL\n");
			break;
		case 10:
			printf("SIGUSR1\n");
			break;

	}




	printf("never quit\n");
}

int main()
{
	signal(SIGINT,SIG_IGN);
	signal(SIGKILL,SIG_IGN);
	signal(SIGUSR1,handler);
	while(1);
	return 0;
}


制作杀死函数的进程的程序

#include <signal.h>
#include <stdio.h>
#include <sys/types.h>

//       typedef void (*sighandler_t)(int);

//       sighandler_t signal(int signum, sighandler_t handler);

int main(int argc, char **argv[])
{

	int signum;
	int pid;

	signum = atoi(argv[1]);
	pid = atoi(argv[2]);
	kill(pid, signum);
	printf("signum: %d pid = %d\n", signum, pid);

	return 0;
}

        kill(pid, signum); 用于杀死进程

 

 信号传递

接收信号

#include <signal.h>
#include <stdio.h>

//       int sigaction(int signum, const struct sigaction *act,
//                     struct sigaction *oldact);
void handler(int signum, siginfo_t *info, void *context)
{
	printf("get sigaction %d\n", signum);
	if (context != NULL) // context 判断是否收到信息
	{
		printf("get data = %d\n", info->si_int);
		printf("set data = %d\n", info->si_value.sival_int);
		printf("pid = %d\n", info->si_pid); // 发送者的pid info 大概就是获取发送者的东西
	}
}

int main()
{
	printf("pid = %d\n", getpid());
	struct sigaction act;
	act.sa_sigaction = handler;		// 收到信号调用handler
	act.sa_flags = SA_SIGINFO;		// 用于接收信号
	sigaction(SIGUSR1, &act, NULL); // null 用来备份 传递构建结构体的地址
	while (1)
		;

	return 0;
}

 发送信号

#include <signal.h>
#include <stdio.h>

//       int sigaction(int signum, const struct sigaction *act,
//                     struct sigaction *oldact);
int main(int argc, char **argv)
{

	int signum = atoi(argv[1]);
	int pid = atoi(argv[2]);
	union sigval value;//自带联合体

	value.sival_int = 100;

	sigqueue(pid, signum, value);//发送信号api 
	printf("done pid  %d\n", getpid());

	return 0;
}

使用这两个收发数据接收数据方

可以获取发送者的数据和pid等信息

信号量

信号量相当于钥匙 信号量集相当于放钥匙的盒子

P操作相当于拿锁

V操作相当于放回锁

semget

semop

semctl


创建信号量示例

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// int semget(key_t key, int nsems, int semflg);
// int semctl(int semid, int semnum, int cmd, ...);
//  int semop(int semid, struct sembuf *sops, unsigned nsops);

union semun
{
    int val;               /* Value for SETVAL */
    struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
    unsigned short *array; /* Array for GETALL, SETALL */
    struct seminfo *__buf; /* Buffer for IPC_INFO  (Linux-specific) */
};
int main(int argc, char const **argv[])
{
    key_t key;
    int semid;
    key = ftok(".", 2);
    semid = semget(key, 1, IPC_CREAT | 0666);//创建信号量
    union semun initsem;
    initsem.val = 1;//操作第0个信号量
    semctl(semid, 0, SETVAL, initsem);//初始化信号量 SETVAL 设置信号量的值 第四个参数必须要联合体
    int pid = fork();//添加进程
    if (pid > 0)
    {
        printf("this is father\n");
    }
    else if (pid == 0)
    {

        printf("this is childen\n");
    }
    else
    {
        printf("error\n");
    }

    return 0;
}

 控制进程的先后案例

#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
// int semget(key_t key, int nsems, int semflg);
// int semctl(int semid, int semnum, int cmd, ...);
//  int semop(int semid, struct sembuf *sops, unsigned nsops);

union semun
{
    int val;               /* Value for SETVAL */
    struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
    unsigned short *array; /* Array for GETALL, SETALL */
    struct seminfo *__buf; /* Buffer for IPC_INFO  (Linux-specific) */
};
void pGetkey(int id)
{
    struct sembuf set; // 创建semop的结构体
    set.sem_num = 0;
    set.sem_op = -1;
    set.sem_flg = SEM_UNDO;
    semop(id, &set, 1);
    printf("get key\n");
}
void vGetkey(int id)
{
    struct sembuf set; // 创建semop的结构体
    set.sem_num = 0;
    set.sem_op = 1;
    set.sem_flg = SEM_UNDO;
    semop(id, &set, 1);
    printf("put back the key\n");
}

int main(int argc, char const **argv[])
{
    key_t key;
    int semid;
    key = ftok(".", 2);
    semid = semget(key, 1, IPC_CREAT | 0666); // 创建信号量 这里只创建一个信号量
    union semun initsem;
    initsem.val = 0;                   // 操作第0个信号量 用于控制锁的产生
    semctl(semid, 0, SETVAL, initsem); // 初始化信号量 SETVAL 设置信号量的值 第四个参数必须要联合体
    int pid = fork();                  // 添加进程
    if (pid > 0)
    {
        pGetkey(semid);
        printf("this is father\n");
        vGetkey(semid);
        semctl(semid, 0, IPC_RMID); // 销毁锁
    }
    else if (pid == 0)
    {

        printf("this is childen\n");
        vGetkey(semid); // 修改信号量的值
    }
    else
    {
        printf("error\n");
    }

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值