1.共享内存
草稿记录:共享内存中,收、发双方均可查看消息的内容
编程实践:
//创建共享内存及向共享内存些入端
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
#include <stdio.h>
#include <unistd.h>
int main()
{
int shmid;
key_t key;
key = ftok(".",1);
char *shmaddr; //指向共享内存的变量,通过这个变量访问共享内存
shmid = shmget(key,1024*4,IPC_CREAT|0666); //创建4m共享内存 给予可读可写权限
if(shmid == -1){ //-1 represent failed
printf("shmget No ok\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0); //完成共享内存映射
printf("shmat Ok\n");
printf("before strcpy,data:%s",shmaddr); //为空
strcpy(shmaddr,"binbin love you"); //向共享内存写入内容
sleep(4);
shmdt(shmaddr); //卸载共享内存
shmctl(shmid,IPC_RMID,0); //将共享内存从内核关闭 RMID 熟悉的面孔
return 0;
}
#include <sys/ipc.h>
#include <sys/shm.h>
#include <string.h>
#include <stdlib.h>
//int shmget(key_t key, size_t size, int shmflg);
#include <stdio.h>
#include <unistd.h>
int main()
{
int shmid;
key_t key;
key = ftok(".",1);
char *shmaddr;
shmid = shmget(key,1024*4,0); //获取共享内存
if(shmid == -1){ //-1 represent failed
printf("shmget No ok\n");
exit(-1);
}
shmaddr = shmat(shmid,0,0);
printf("shmat Ok\n");
printf("data:%s",shmaddr);
sleep(4);
shmdt(shmaddr);
printf("quit\n");
return 0;
}
补充:终端 查看所有共享内存方法: ipcs -m
删除指定进程 :ipcs -m 共享内存id号
2.信号
用于通知接收信号的进程有某种事件发生,所以可用于进程间通信;除了用于进程间通信之外,进程还可以发送信号给进程本身。
动手实现发送信号应用:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc,char **argv)
{
int signum;
int pid;
signum = atoi(argv[1]);
pid = atoi(argv[2]);
int a = 10;
union sigval value;
value.sival_int = a;
sigqueue(pid,signum,value);//signum 是我们的第二个命令行参数随便输入一个数 是哪个用户的意思 pid是我们的第三个命令行参数
printf("%d,done\n",getpid());
return 0;
}
接收信号:
#include <signal.h>
//int sigaction(int signum, const struct sigaction *act,
// struct sigaction *oldact);
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void handler(int signum,siginfo_t *info,void*context)
{
printf("get signum:%d\n",info->si_pid);
if(context != NULL){
printf("get data=%d\n",info->si_int);
printf("get data=%d\n",info->si_value.sival_int);
}
}
int main()
{
struct sigaction act;
printf("pid = %d\n",getpid());
act.sa_sigaction = handler;
act.sa_flags = SA_SIGINFO;//be able to get massage
sigaction(SIGUSR1,&act,NULL);
while(1);
return 0;
}
接收信号代码编译为Nicesignal并执行:
发送信号代码编译为Nicesend并执行:./Nicesend 10 15270
运行结果为:
3.消息队列
消息队列是消息的链表, 存放在内核中并由消息队列标识符标识, 消息队列克服了信号传递信息少、 管道只能承载无格式字节流以及缓冲区大小受限等缺陷。 消息队列包括 POSIX 消息队列和 System V 消息队列。消息队列是 UNIX 下不同进程之间实现共享资源的一种机制, UNIX 允许不同进程将格式化的数据流以消息队列形式发送给任意进程, 有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。
写入(读取)队列一方:
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
struct msgbuf{
long mtype;//消息类型
char mtext[128];//massage data
};
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//int msgget(key_t key, int msgflg);
int main()
{
struct msgbuf sendBuf={888,"this is massage from queue"};
struct msgbuf readBuf;
key_t key;
key = ftok(".",'z');
printf("key:%x\n",key);
int msg_id = msgget(key,IPC_CREAT|0777);//duiliecsu meiyoujiuchuangjian duiliehao
if(msg_id == -1){
printf("get queue failed\n");
}
msgsnd(msg_id,&sendBuf,strlen(sendBuf.mtext),0);
printf("send over;\n");
msgrcv(msg_id,&readBuf,sizeof(readBuf.mtext),988,0);
printf("return from que:%s\n",readBuf.mtext);
msgctl(msg_id,IPC_RMID,NULL);
//send massage
return 0;
}
读取(写入)队列一方:
#include <stdio.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <string.h>
struct msgbuf{
long mtype;//消息类型
char mtext[128];//massage data
};
//ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);
//int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
//int msgget(key_t key, int msgflg);
int main()
{
struct msgbuf sendBuf={888,"this is massage from queue"};
struct msgbuf readBuf;
key_t key;
key = ftok(".",'z');
printf("key:%x\n",key);
int msg_id = msgget(key,IPC_CREAT|0777);//创建消息队列并返回队列id
if(msg_id == -1){
printf("get queue failed\n");
}
msgrcv(msg_id,&readBuf,sizeof(readBuf.mtext),888,0);//sort is 888
printf("get from que:%s\n",readBuf.mtext);
struct msgbuf sendbuf={988,"thanks for reach"};
msgsnd(msg_id,&sendbuf,strlen(sendbuf.mtext),0);
msgctl(msg_id,IPC_RMID,NULL); //发送方需销毁
return 0;
}
4.信号量
信号量是一个计数器, 与其它进程间通信方式不大相同, 它主要用于控制多个进程间或一个进程内的多个线程间对共享资源的访问, 相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志, 除了用于共享资源的访问控制外,还可用于进程同步。它常作为一种锁机制(一个进程归还锁、一个进程需要钥匙并归还锁), 防止某进程在访问资源时其它进程也访问该资源, 因此, 主要作为进程间以及同一个进程内不同线程之间的同步手段。 Linux 提供了一组精心设计的信号量接口来对信号量进行操作,它们声明在头文件 sys/sem.h 中,有空可以去研究一下。
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <unistd.h>
//api:
//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;
set.sem_num = 0;
set.sem_op = -1;
set.sem_flg=SEM_UNDO;
semop(id, &set ,1);
printf("getkey\n");
}
void vPutBackKey(int id)
{
struct sembuf set;
set.sem_num = 0;
set.sem_op = 1;
set.sem_flg=SEM_UNDO;
semop(id, &set ,1);
printf("put back the key\n");
}
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设置信号量的值,设置为inisem
int pid = fork();
if(pid > 0){
//去拿锁
pGetKey(semid);
printf("this is father\n");
vPutBackKey(semid);
//锁放回去
semctl(semid,0,IPC_RMID);
}
else if(pid == 0){
printf("this is child\n");
vPutBackKey(semid);
}else{
printf("fork error\n");
}
return 0;
}