资源描述
<观察实验>实验报告
题目:观察实验
1、实验目的与内容
在Linux下,用ipcs()命令观察进程通信情况,了解Linux基本通信机制。
2、实验原理
Linux IPC继承了Unix System V及DSD等,共有6种机制: 信号(signal)、管道(pipe和命名管道(named piped)、消息队列(message queues)、共享内存(shared memory segments)、信号量(semaphore)、套接字(socket)。
本实验中用到的几种进程间通信方式:
(1)共享内存段(shared memory segments)方式
– 将2个进程的虚拟地址映射到同一内存物理地址,实现内存共享
– 对共享内存的访问同步需由用户进程自身或其它IPC机制实现(如信号量)
– 用户空间内实现,访问速度最快。
– Linux利用shmid_ds结构描述所有的共享内存对象。
(2)信号量(semaphore)方式
– 实现进程间的同步与互斥
– P/V操作, Signal/wait操作
– Linux利用semid_ds结构表示IPC信号量
(3)消息队列(message queues)方式
– 消息组成的链表,进程可从中读写消息。
– Linux维护消息队列向量表msgque,向量表中的每个元素都有一个指向msqid_ds结构的指针,每个msqid_ds结构完整描述一个消息队列.
LINUX系统提供的IPC函数有:
l msgget(关键字,方式):创建或打开一个消息队列
l msgsnd(消息队列标志符,消息体指针,消息体大小,消息类型):向队列传递消息
l msgrcv(消息队列标志符,消息体指针,消息体大小,消息类型):从队列中取消息
l msgctl(消息队列标志符,获取/设置/删除,maqid_ds缓冲区指针):获取或设置某个队列信息,或删除某消息队列
Linux系统中,内核,I/O任务,服务器进程和用户进程之间采用消息队列方式,许多微内核OS中,内核和各组件间的基本通信也采用消息队列方式.
3.实验内容:
查看共享信息的内存的命令是ipcs [-m|-s|-q]。
默认会列出共享内存、信号量,队列信息,-m列出共享内存,-s列出共享信号量,-q列出共享队列
清除命令是ipcrm [-m|-s|-q] id。
-m 删除共享内存,-s删除共享信号量,-q删除共享队列。
ipcs -a或ipc 显示当前系统中共享内存段、信号量集、消息队列的使用情况;
ipcs -m 显示共享内存段的使用情况;
ipcs -s 显示信号量集的使用情况;
ipcs -q 显示消息队列的使用情况;
ipcrm可用来删除对应的共享内存段、信号量、消息队列;
ipcrm -s semid 删除对应的信号量集
ipcrm -m shmid 删除对应的共享内存段
ipcrm -q msqid 删除对应的消息队列
共享内存大小查看
# cat /proc/sys/kernel/shmmax
共享内存段有时不能马上删除,需使用这个内存段的所有进程向OS发送detach命令时才有释放,此时可以考虑删除进程使用的信号量,帮助释放共享内存段
编写测试源程序如下:
注:这个程序中,父进程会将三条消息发送到消息队列,子进程在等待60秒后,再收接消息.
在60秒中,消息存在于消息队列,以便于我们查看.
测试源程序文本:(消息队列方式)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/msg.h>
#include <sys/ipc.h>
struct message {
long int mtype;
char mtext[128];
};
int send_msg(int qid, int mtype, const char text[]){
struct message msg = {
.mtype = mtype
};
strncpy (msg.mtext, text, sizeof(msg.mtext));
int r = msgsnd(qid, &msg, sizeof(msg), 0);
if (r == -1){
perror("msgsnd");
}
}
void producer(int mqid)
{
send_msg(mqid, 1, "type 1 - first");
send_msg(mqid, 2, "type 2 - second");
send_msg(mqid, 1, "type 1 - third");
}
void consumer(int qid)
{
struct message msg;
int r;
int i;
for (i = 0;i<3; i++){
r = msgrcv(qid, &msg, sizeof(struct message), -2, 0);
printf("'%s'\n", msg.mtext);
}
}
int main (int argc, char *argv[])
{
int mqid;
mqid = msgget (IPC_PRIVATE, S_IREAD|S_IWRITE);
if (mqid == -1) {
perror("msgget");
exit (1);
}
pid_t pid = fork();
if (pid == 0){
sleep(60);
consumer(mqid);
exit (0);
}
else{
int status;
producer(mqid);
wait(&status);
}
int r = msgctl(mqid, IPC_RMID, 0);
if (r)
perror("msgctl");
return 0;
}
系统信号量方式:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/sem.h>
int
main (int argc, char *argv[])
{
key_t semkey = ftok("/tmp", 'a');
int semid =
semget(semkey, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
if(semid != -1){
printf("Created new semaphore\n");
}
else
if(errno == EEXIST){
printf("semaphore exists\n");
semid = semget(semkey, 1, 0);
}
assert(semid != -1);
if (argc == 2){
int op = atoi(argv[1]);
struct sembuf sb={
.sem_num = 0,
.sem_op = op,
.sem_{敏感词} = 0
};
int r = semop (semid,&sb,1);
assert(r != -1);
printf("Operation %d done\n", op);
}
else {
printf("no operation \n");
}
printf("semid %d value %d\n", semid ,semctl(semid,0,GETVAL));
return 0;
}
共享内存方式:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
void error_out(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
int main (int argc, char *argv[])
{
key_t mykey = 12345678;
const size_t region_size = sysconf(_SC_PAGE_SIZE);
int smid = shmget(mykey, region_size, IPC_CREAT|0666);
if(smid == -1)
error_out("shmget");
void *ptr;
ptr = shmat(smid, NULL, 0);
if (ptr == (void *) -1)
error_out("shmat");
pid_t pid = fork();
if (pid == 0){
u_long *d = (u_long *)ptr;
*d = 0xdeadbeef;
exit(0);
}
else{
int status;
waitpid(pid, &status, 0);
printf("child wrote %#lx\n", *(u_long *)ptr);
}
sleep(30);
int r = shmdt(ptr);
if (r == -1)
error_out("shmdt");
r = shmctl(smid, IPC_RMID, NULL);
if (r == -1)
error_out("shmdt");
return 0;
}
展开阅读全文