測試源程序如下:
#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);
}
{
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
終端1)
./smem
child wrote 0xdeadbeef
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,這意味着關聯着的進程仍可合法存取這端內存,但是它不能再被新的進程關聯了.
此時該段的共享內存鍵值將會是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
運行ipcs -m查看共享內存,程序進入第一個sleep(30);,此時status爲空
ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00bc614e 0 root 666 4096 1
ipcrm -m 32768
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 32768 root 666 4096 1 dest
最後smem再過30秒後,運行了shmctl(smid, IPC_RMID, NULL);刪除共享內存,這時會報錯shmdt: Invalid argument,因爲我們手工刪除了共享內存,
又程序到最後再去刪除共享內存,所以報錯.
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()修改共享內存段的時間.
用ipcs調試消息隊列.
測試源程序如下:
#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>
long int mtype;
char mtext[128];
};
struct message msg = {
.mtype = mtype
};
strncpy (msg.mtext, text, sizeof(msg.mtext));
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");
}
{
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 mqid;
mqid = msgget (IPC_PRIVATE, S_IREAD|S_IWRITE);
if (mqid == -1) {
perror("msgget");
exit (1);
}
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;
}
gcc mesg.c -o mesg
在60秒中,消息存在於消息隊列,以便於我們查看.
./mesg&
ipcs -q
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 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 來刪除消息隊列
用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>
main (int argc, char *argv[])
{
key_t semkey = ftok("/tmp", 'a');
semget(semkey, 1, IPC_CREAT|IPC_EXCL|S_IRUSR|S_IWUSR);
printf("Created new semaphore\n");
}
else
if(errno == EEXIST){
printf("semaphore exists\n");
semid = semget(semkey, 1, 0);
}
if (argc == 2){
int op = atoi(argv[1]);
.sem_num = 0,
.sem_op = op,
.sem_{敏感詞} = 0
};
}
else {
printf("no operation \n");
}
return 0;
}
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
./sysv_sem 1
semaphore exists
Operation 1 done
semid 196608 value 1
ipcs -s
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個信號量.
ipcs -s -i 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
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,表示有一個進程等待信號量值增加.
例如我們使當前的信號量值大於0,此時指定op的值爲0,這時將會阻塞,直到這個信號量變爲0,在阻塞期間等待信號量變成零的進程個數就是zcount,如下:
增加信號量值爲1.
./sysv_sem 1
semaphore exists
Operation 1 done
semid 425984 value 0
./sysv_sem 0
semaphore exists
此時阻塞.
ipcs -s -i 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,表示有一個進程等待信號量值變爲零.
cat /proc/sys/kernel/sem
250 32000 32 128
第一列,表示每個信號集中的最大信號量數目.
第二列,表示系統範圍內的最大信號量總數目.
第三列,表示每個信號發生時的最大系統操作數目.
第四列,表示系統範圍內的最大信號集總數目.