linux調試工具ipcs的深入分析

來源:互聯網
上載者:User
1)system v系統共用記憶體用ipcs調試共用記憶體測試來源程式如下:
#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;
}編譯:
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 <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;
}編譯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 294912Message 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 <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;
}編譯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 196608Semaphore 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 425984Semaphore 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 425984Semaphore 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
第一列,表示每個訊號集中的最大訊號量數目.
第二列,表示系統範圍內的最大訊號量總數目.
第三列,表示每個訊號發生時的最大系統運算元目.
第四列,表示系統範圍內的最大訊號集總數目.
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.