用ipcs调试共享内存

测试源程序如下:

#include #include #include #include #include #include #include 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;

}

编译:

gcc smem.c -o smem

注:这个程序会申请共享内存,父子进程都会向共享内存写数据,达到IPC通讯的目的.

终端1)

./smem

child wrote 0xdeadbeef

终端2)

ipcs -m

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status

0x00bc614e 18874397   root       666        4096       1

注:

key栏中列出的信息是应用程序定义的键值,如果是私有对象的键值则为0,在这里我们定义键值为12345678,也就是输出的0x00bc614e(十六进制)

shmid栏中列出共享内存的ID,这个值是唯一的.

owner栏中列出创建共享内存的用户是root.

perms栏中列出共享内存的权限.

bytes栏中列出这块共享内存的大小,我们通过调用sysconf(_SC_PAGE_SIZE)得到要创建的共享内存大小为4096个字节.

nattch栏中列出连接在关联的共享内存段的进程数.

status栏中列出当前共享内存的状态,当该段内存的mode字段设置了SHM_DEST位时就会显示"dest"字样,

当用户调用shmctl的IPC_RMID时,内核首先看有多少个进程还和这段内存关联着,如果关联数为0,就会销毁(释放)这段内存,否则就设置这段内存的mode位SHM_DEST,

并设置它的key为IPC_PRIVATE,这意味着关联着的进程仍可合法存取这端内存,但是它不能再被新的进程关联了.

在上面的输出中,我们没有看到smem用到的共享内存有dest的状态,而此时我们用ipcrm -m 18874397手工删除该段共享内存时,

此时该段的共享内存键值将会是0x00000000(IPC_PRIVATE),而程序通过调用shmdt来释放该段共享内存时,这段共享内存才会真正的消失.

为完成这个测试,我们修改上面的程序,在shmdt()后面增加:

printf("shmdt function run finished\n");

sleep(30);

在shmctl函数后面增加:

printf("shmctl function run finished\n");

终端1,重新编译,运行

gcc smem.c -o smem

./smem

child wrote 0xdeadbeef

终端2

运行ipcs -m查看共享内存,程序进入第一个sleep(30);,此时status为空

ipcs -m

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status

0x00bc614e 0          root      666        4096       1

删除shmid为32768的共享内存,此时status为dest,而key变为0x00000000

ipcrm -m 32768

------ Shared Memory Segments --------

key        shmid      owner      perms      bytes      nattch     status

0x00000000 32768      root      666        4096       1          dest

过30秒后,此时程序运行了shmdt函数释放共享内存,我们用ipcs -m再看不到该共享内存,虽然它没有运行到shmctl(smid, IPC_RMID, NULL);

最后smem再过30秒后,运行了shmctl(smid, IPC_RMID, NULL);删除共享内存,这时会报错shmdt: Invalid argument,因为我们手工删除了共享内存,

又程序到最后再去删除共享内存,所以报错.

我们通过ipcs -mi 32768可以看到更详细的信息,如下:

Shared memory Segment shmid=327680

uid=0   gid=0   cuid=0  cgid=0

mode=0666       access_perms=0666

bytes=4096      lpid=3263       cpid=3263       nattch=0

att_time=Mon Mar 14 09:42:52 2011

det_time=Mon Mar 14 09:43:22 2011

change_time=Mon Mar 14 09:42:52 2011

注:

cuid=0代表创建这个共享内存的用户ID为0

cgid=0代表创建这个共享内存的组ID为0

lpid=3263代表最后一次访问这个共享内存段的PID为3263

cpid=3263代表最后一产创建这个共享内存段的PID为3263

att_time=Mon Mar 14 09:42:52 2011代表最后一次调用shmat()的时间

det_time=Mon Mar 14 09:43:22 2011代表最后一次调用shmdt()的时间

change_time=Mon Mar 14 09:42:52 2011代表最后一次用shmctl()修改共享内存段的时间.

最后system v共享内存的最大值可以通过修改/proc/sys/kernel/shmmax进行调整.

2)system v系统消息队列

用ipcs调试消息队列.

测试源程序如下:

#include #include #include #include #include #include #include #include #include

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;

}

编译mesg.c

gcc mesg.c -o mesg

注:这个程序中,父进程会将三条消息发送到消息队列,子进程在等待60秒后,再收接消息.

在60秒中,消息存在于消息队列,以便于我们查看.

执行mesg

./mesg&

ipcs -q

------ Message Queues --------

key        msqid      owner      perms      used-bytes   messages

0x00000000 229376     root       600        408          3

注:

key栏中列出的信息是应用程序定义的键值.

msgid栏中列出的值是系统定义的键值.

正如所期望的,系统定义的键值是唯一的,而在本例中应用程序定义的键值全部是0,这意味着这些消息队列是使用IPC_PRIVATE键值创建的.

owner栏中列出创建消息队列的用户是root.

perms栏中列出这个消息队列的权限.

used-bytes栏中列出这个消息队列所占用的空间大小,在这里我们的结构体:

struct message {

long int mtype;

char mtext[128];

};

long int mtype占用8个字节,因为它是64位系统,如果是32位系统,它占用的字节为4个,

char mtext[128]占用128个字节,也就是一条消息就是136,三条消息正好是408.

messages栏中列出这条消息队列中有几条消息,我们发送了三条消息,所以这里正好是3.

用ipcs -q -i PID的方式可以看到更详细的信息,如下面:

ipcs -q -i 294912

Message Queue msqid=294912

uid=0 gid=0 cuid=0 cgid=0 mode=0600

cbytes=408 qbytes=16384 qnum=3 lspid=4036 lrpid=0

send_time=Fri Mar 11 20:52:21 2011

rcv_time=Not set

change_time=Fri Mar 11 20:52:21 2011

注:

cuid一栏列出创建这个消息队列的用户ID

cgid一栏列出创建这个消息队列的组ID

qbytes一栏列出SYSTEM V消息队列的最大值,可以通过修改/proc/sys/kernel/msgmnb和/proc/sys/kernel/msgmax进行调整.

lspid一栏列出最后一个发送消息到这个消息队列的进程.

lrpid一栏列出最后一个从这个消息队列接收消息的进程.

send_time一栏列出发送消息到这个消息队列的最后时间.

rcv_time一栏列出从这个消息队列接收消息的最后时间.

change_time一栏列出更改这个消息队列的最后时间.

最后可以用ipcrm -q 来删除消息队列

3)system v系统的信号量

用ipcs调试信号量

测试源程序如下:

#include #include #include #include #include #include #include #include

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;

}

编译sysv_sem.c

gcc sysv_sem.c -o sysv_sem

注:

这个程序通过semget函数创建了一个信号量集,semop函数操作了信号量集中的一个集号,这样来增加或减少信号量中含的值,从而达到程序同步和资源互斥的目的.

执行程序,此时创建了一个信号量,初始值.sem_num为0,所以它通过semctl函数获取的值为0.

./sysv_sem 0

Created new semaphore

Operation 0 done

semid 196608 value 0

执行程序,将参数换成1,此时它的值为1,如下:

./sysv_sem 1

semaphore exists

Operation 1 done

semid 196608 value 1

用ipcs -s来查看信号量信息,如下:

ipcs -s

------ Semaphore Arrays --------

key        semid      owner      perms      nsems

0x61018001 196608     root      600        1

注:

key栏中列出的信息是应用程序定义的键值,这里我们用ftok来生成它的ID.

semid栏中列出系统定义的键值.

owner栏中列出创建该信号量集的用户是root

perms栏中列出这个信号量集的权限.

nsems栏中列出这个信号量集中指定了多少个信号量,我们的例子中指定了1个,可以通过semget函数指定多个,如:

segmet(semkey, 5, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);

这样就在这个信号集中指定了5个信号量.

用-i参数可以看到更详细的信息,如下;

ipcs -s -i 196608

Semaphore Array semid=196608

uid=0    gid=0   cuid=0  cgid=0

mode=0600, access_perms=0600

nsems = 1

otime = Tue Mar 15 11:44:49 2011

ctime = Tue Mar 15 11:43:38 2011

semnum     value      ncount     zcount     pid

0          1          0          0          2791

注:

cuid=0列出创建这个信号量集的用户ID.

cgid=0列出创建这个信号量集的组ID.

mode=0600列出创建这个信号量集时的权限.

access_perms=0600列出这个信号量集的访问权限.

otime = Tue Mar 15 11:44:49 2011列出这个信号量集的访问操作时间,如semop函数对信号量集的操作.

ctime = Tue Mar 15 11:43:38 2011列出这个信号量集的创建时间,如semget函数创建这个信号量集.

semnum列出了信号量集中信号量的序列,如果我们在semget函数中指定了两个信号量,这里的输出,将会是下面的信息:

semnum     value      ncount     zcount     pid

0          8          0          0          3270

1          0          0          0          0

ncount列出等待信号量增加的进程的个数.

例如我们指定op为负值,此时负值的绝对值大于当前的信号量值,这时将会阻塞,也就是等待资源的进程数会增加,如下:

./sysv_sem -6

semaphore exists

此时阻塞.

我们在另一个终端下查看当前的信号量集,如下:

ipcs -s -i 425984

Semaphore Array semid=425984

uid=0    gid=0   cuid=0  cgid=0

mode=0600, access_perms=0600

nsems = 2

otime = Tue Mar 15 12:14:06 2011

ctime = Tue Mar 15 12:08:15 2011

semnum     value      ncount     zcount     pid

0          0          1          0          3337

1          0          0          0          0

此时等待信号量增加的进程个数为1,即ncount为1,表示有一个进程等待信号量值增加.

zcount列出正在等待信号量变成零的进程的个数

例如我们使当前的信号量值大于0,此时指定op的值为0,这时将会阻塞,直到这个信号量变为0,在阻塞期间等待信号量变成零的进程个数就是zcount,如下:

增加信号量值为1.

./sysv_sem 1

semaphore exists

Operation 1 done

semid 425984 value 0

再次运行sysv_sem程序,指定op为0

./sysv_sem 0

semaphore exists

此时阻塞.

我们在另一个终端查看当前的信号量集,如下:

ipcs -s -i 425984

Semaphore Array semid=425984

uid=0    gid=0   cuid=0  cgid=0

mode=0600, access_perms=0600

nsems = 2

otime = Tue Mar 15 12:23:19 2011

ctime = Tue Mar 15 12:08:15 2011

semnum     value      ncount     zcount     pid

0          1          0          1          3499

1          0          0          0          0

此时等待信号量变成零的进程个数为1,即zcount为1,表示有一个进程等待信号量值变为零.

最后我们可以修改/proc/sys/kernel/sem,来达到修改信号量最大数及相关限制的目的.

例如:

cat /proc/sys/kernel/sem

250     32000   32      128

第一列,表示每个信号集中的最大信号量数目.

第二列,表示系统范围内的最大信号量总数目.

第三列,表示每个信号发生时的最大系统操作数目.

第四列,表示系统范围内的最大信号集总数目.

linux共享内存原IPCS,linux调试工具ipcs的深入分析相关推荐

  1. linux共享内存原IPCS,共享内存相关(ipcs/ipcrm)

    在Linux进程通信中,共享内存的应用是比较普遍,把自己学习过的资料作一个小结吧! 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区.在/proc/sys/kernel/目录下,记录着共 ...

  2. linux共享内存 dest,关于linux 共享内存查看已经完整释放

    完整删除共享内存脚本 #!/bin/sh function rmshm() { zero_status=`ipcs -m|awk '{print $6}'|grep -w 0|wc -l` if [ ...

  3. linux 共享内存为分配,Linux在x86_64上共享内存分配

    我有64位REHL linux,Linux Linux ipms-sol1 2.6.32-71.el6.x86_64#1 SMP x86_64 x86_64 x86_64 GNU / Linux RA ...

  4. linux 共享内存函数封装,linux ftok()函数 --多进程IPC之共享内存

    系统创建IPC通信(如消息队列.共享内存时)必须指定一个ID值.一般状况下,该id值经过ftok函数获得. ftok原型以下: key_t ftok( char * fname, int id ) f ...

  5. linux 共享内存陷井,linux共享内存应用与陷阱

    共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区.在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区 ...

  6. Linux共享内存和信号量,Linux共享内存和信号量的实例(2)

    nbsp;    //SLEEP 3秒,等待消费者进程执行完毕 printf("Poducer if over\n"); exit(0); } else { /*  消费者A进程  ...

  7. linux 共享内存 查看和删除

    在使用共享内存的程序异常退出时,由于没有释放掉共享内存,在调试时会出现错误.您可以使用shell命令来查看与释放已经分配的共享内存,下面将详细说明如何进行查看和释放分配的共享内存的方法. 预备知识 L ...

  8. linux 共享内存 shmget

    专栏内容:linux下并发编程 个人主页:我的主页 座右铭:天行健,君子以自强不息:地势坤,君子以厚德载物. 目录 前言 概述 原理机制 系统命令 接口说明 代码演示 结尾 前言 本专栏主要分享lin ...

  9. c++ 共享内存_关于Linux共享内存的实验 [二] - 原因

    关于Linux共享内存的实验 [一] 上文采用的"删文件"和"杀进程"的方法主要是为了快速演示实验现象,但这种做法不利于通过调试手段进一步探究其内在的逻辑.为此 ...

最新文章

  1. Microsoft Azure云服务停机!系水泵未知原因关闭导致
  2. 第一节:数据库与数据仓库
  3. C#配置及使用log4net
  4. SLF4J简介与使用(整合log4j)
  5. 瑞士科学家造出了撞不坏的无人机丨Science Robitics
  6. Beta阶段第1周/共2周 Scrum立会报告+燃尽图 06
  7. Linux入门相关基础知识
  8. linux常见命令用法之(二)
  9. 酷狗、QQ音乐歌词转换工具
  10. vc 判断哪个按键 被按下 消息 按键 状态
  11. POJ - 3713 (Transferring Sylla)
  12. 使用dynamic_cast报错source type is not polymorphic
  13. 网站建设需要多少钱 开发一个网站有哪些费用
  14. 【学习总结】-Apsara Clouder专项技能认证:实现调用API接口学习总结
  15. MySQL中CONCAT()函数用法详解
  16. Python SDK是什么
  17. java水果忍者7723_水果忍者v1.7.6版
  18. 2023最值得推荐的电脑数据迁移方法,一键转移文件和程序
  19. 服务器负载均衡是什么?有什么用?
  20. 从人脸识别到行人重识别,下一个风口

热门文章

  1. 第八周存款利息计算器
  2. 请问在日本当一名程序员能挣多少钱啊
  3. 基于风险的测试学习总结
  4. smartclient(barcode system)
  5. 艾美捷曲妥珠单抗Trastuzumab化学性质和特异性说明
  6. Ubuntu 添加用户,分配 root权限
  7. python复数的作用_python复数
  8. SpringCloud (一) ——认识微服务
  9. 213维恩图和集合图(VennUpset)
  10. 【12】linux命令每日分享——echo命令为用户添加密码