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;
}