2014年7月17日星期四

semop和ipcs

说起semop函数,其实man手册都说得比较清楚了,其作用就是对信号量进行PV操作。平时使用的时候参考手册就可以,但是如果结合ipcs命令的话就可以更直观的看到信号量的变化。

上代码:
001 C++语言高亮代码由发芽网提供
002 #include <stdlib.h>
003 #include <stdio.h>
004 #include <unistd.h>
005 #include <stdint.h>
006 #include <semaphore.h>
007 #include <sys/ipc.h>
008 #include <sys/shm.h>
009 #include <sys/types.h>
010 #include <sys/socket.h>
011 #include <sys/wait.h>
012 #include <sys/stat.h>
013 #include <sys/time.h>
014 #include <sys/sem.h>
015 #include <netinet/in.h>
016 #include <arpa/inet.h>
017 #include <signal.h>
018 #include <string.h>
019 #include <stdarg.h>
020 #include <netdb.h>
021 #include <iostream>
022 #include <sstream>
023 #include <map>
024 #include <cstdarg>  //var_list
025 
026 #include <fcntl.h>
027 #include <dlfcn.h>
028 #include <errno.h>
029 
030 using namespace std;
031 
032 void sem_P(int semid)
033 {
034   int ret = -1;
035   struct sembuf buf;
036   buf.sem_num = 0;
037   buf.sem_op = -1;
038   buf.sem_flg = SEM_UNDO;//退出时会撤销此次操作
039   // buf.sem_flg = 0;//如果是0则不会撤销
040 
041   errno = 0;
042   while (((ret = semop(semid, &buf, 1)) < 0) && (errno == EINTR)) ;
043 }
044 
045 void sem_P2(int semid)
046 {
047   struct sembuf sops[2];
048   int ret = -1;
049   sops[0].sem_num = 0;
050   sops[0].sem_op = 0;
051   sops[0].sem_flg = 0;
052 
053   sops[1].sem_num = 0;
054   sops[1].sem_op = 1;
055   sops[1].sem_flg = 0;
056 
057   errno = 0;
058   while (((ret = semop(semid, sops, 2)) < 0) && (errno == EINTR)) ;
059 }
060 
061 void sem_V(int semid)
062 {
063   int ret = -1;
064   struct sembuf buf;
065   buf.sem_num = 0;
066   buf.sem_op = 1;
067   buf.sem_flg = SEM_UNDO;
068   // buf.sem_flg = 0;
069 
070   errno = 0;
071   while (((ret = semop(semid, &buf, 1)) < 0) && (errno == EINTR)) ;
072 }
073 
074 int main(int argc, char *argv[])
075 {
076   int m_semid = -1;
077 
078   //生成key值
079   const char *path = "/tmp";
080   key_t key = ftok(path, 11);
081   if (key < 0) {
082       return 1;
083   }
084   printf("key %d\n", key);
085 
086   //生成新的信号量
087   int new_sem = 1;
088   int semid = semget(key, 1, IPC_CREAT | IPC_EXCL | 0666);
089   if (semid < 0) {
090       printf("semget error %d\r\n", semid);
091       if (errno == EEXIST) {
092           new_sem = 0;
093           semid = semget(key, 1,  0666);
094           printf("semget exist %d\r\n", semid);
095           if (semid < 0) {
096               return 1;
097           }
098       } else {
099           return 1;
100       }
101   }
102 
103   printf("semid %d \r\n", semid);
104 
105   //设置新的信号量值为1
106   if (new_sem) {
107       if (semctl(semid, 0, SETVAL, 1) < 0) {
108           printf("semctl err.\r\n");
109           semctl(semid, 0, IPC_RMID);
110           return 1;
111       }
112   }
113 
114  //这里用ipcs命令可以看到信号量值为1
115  printf("before sem_p \r\n");
116  sleep(10);
117  
118   sem_P(semid);
119   printf("sem_P ok \r\n");
120 
121 
122   //这里用ipcs命令可以看到信号量值为0
123   sleep(15);
124   printf("end \r\n");
125 
126   return 0;
127 
128 }

编译后运行程序,程序在115行会sleep一下,这时候用ipcs -s -i semid 命令就可以看到信号量的值是1的(semid程序运行时已经打出来了):
程序运行结果:
key 184644993
semget error -1
semget exist 5668871
semid 5668871 
before sem_p 
sem_P ok 
end 

1.可以看到semid是5668871,在打印出“before sem_p ”的时候用命令ipcs -s -i 5668871,结果:
--------------------------------------------------
Semaphore Array semid=5668871
uid=0 gid=0 cuid=0 cgid=0
mode=0666, access_perms=0666
nsems = 1
otime = Thu Jul 17 11:38:55 2014  
ctime = Wed Jul 16 17:48:24 2014  
semnum     value      ncount     zcount     pid       
0          1          0          0          3009  
--------------------------------------------------
最后一行value就是信号量的值(1)了

2.在打印出“sem_P ok ”的时候,再用ipcs -s -i 5668871 来看,结果:
--------------------------------------------------
Semaphore Array semid=5668871
uid=0 gid=0 cuid=0 cgid=0
mode=0666, access_perms=0666
nsems = 1
otime = Thu Jul 17 16:40:18 2014  
ctime = Wed Jul 16 17:48:24 2014  
semnum     value      ncount     zcount     pid       
0          0          0          0          30155 
-------------------------------------------------------
可以看到vlaue已经变成了0,同时pid也变成了我们程序的pid

3.程序运行结束后,我们再使用ipcs命令来看看:
---------------------------------------------------
Semaphore Array semid=5668871
uid=0 gid=0 cuid=0 cgid=0
mode=0666, access_perms=0666
nsems = 1
otime = Thu Jul 17 16:40:33 2014  
ctime = Wed Jul 16 17:48:24 2014  
semnum     value      ncount     zcount     pid       
0          1          0          0          30155    
-----------------------------------------------------------
信号量的value又变成了1,为啥呢?因为在sem_P函数里面我们指定了进程退出时对信号量的操作buf.sem_flg = SEM_UNDO,就是我们在程序里面对信号量减一了,退出后这个操作就会被撤销了。

哈哈,这样看起来是不是清楚多了。

另外,在sem_P2函数里面还有对一个信号量进行了两次操作,先是等待信号量变成0,然后再对信号量进行加1。这也是一个蛮有意思的操作。

没有评论:

发表评论