[<<Previous Entry]
[^^Up^^]
[Next Entry>>]
[Menu]
[About The Guide]
ëÏÌØÃÅ×ÁÑ ÏÞÅÒÅÄØ, ÒÅÁÌÉÚÏ×ÁÎÎÁÑ × ÒÁÚÄÅÌÑÅÍÏÊ ÐÁÍÑÔÉ
ðòïéú÷ïäéôåìø, ðéûõýéê ÷ ëïìøãå÷õà ïþåòåäø, prod_qshm.c :
1 /* producer program:
2 a circular queue of fixed size items is implemented in
3 shared memory.
4 producer puts items at tail of queue.
5 consumer gets items from head of queue.
6 DELIMITER entry indicates to consumer that producer is done.
7 DELIMITER produced upon receipt of SIGINT signal.
8 semaphore used to ensure mutually exclusive queue update.
9 */
10 #include <stdio.h>
11 #include <sys/types.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <sys/ipc.h>
15 #include <sys/sem.h>
16 #include <sys/shm.h>
17 #include <signal.h>
18 #include <setjmp.h>
19 #include <string.h>
20 #include <time.h>
21 #define QUE_SZ 5
22 #define MSG_SZ 30
23 struct CIRC_QUE {
24 int head;
25 int tail;
26 char msg[QUE_SZ][MSG_SZ];
27 };
28 static struct CIRC_QUE *q_shm;
29 #define QUE_FULL -1
30 #define PUT_SUCCESS 0
31 static char *pname;
32 static int semid, shmid;
33 static struct sembuf lock = { 0, -1, 0};
34 static struct sembuf unlock = { 0, 1, 0};
35 static jmp_buf bef_put_que;
36 static int set = 0;
37 static char localmsg[MSG_SZ];
38 #ifdef DEBUG
39 static void print_que(struct CIRC_QUE *qptr, char *label);
40 #endif
41 static void rpterror(char *string);
42 static void wrap_up(int);
43 static void postdelim(int);
44 static int put_que(void);
45
46 main(int argc, char *argv[])
47 {
48 struct shmid_ds shmstat;
49 char semid_str[15], shmid_str[15];
50
51 pname = argv[0];
52
53 setbuf(stdout, NULL);
54
55 if((semid=semget(IPC_PRIVATE, 1, IPC_CREAT | 0660)) == -1)
56 rpterror("semget()");
57 exit(2);
58 }
59
60 semctl(semid, 0, SETVAL, 1); /* initialize semaphore to unlock
*/
61
62 shmid=shmget(IPC_PRIVATE, sizeof(struct CIRC_QUE),IPC_CREAT|0660);
63 if(shmid == -1){
64 rpterror("shmget()");
65 exit(3);
66 }
67
68 switch(fork())
69 {
70 case 0:
71 sprintf(semid_str,"%d",semid);
72 sprintf(shmid_str,"%d",shmid);
73 execl("cons_qshm","q_consumer",semid_str,shmid_str,0);
74 perror("exec failed");
75 wrap_up(2);
76 case -1:
77 perror("fork failed");
78 wrap_up(3);
79 }
80
81 q_shm = shmat(shmid, 0, 0);
82
83 sigset(SIGINT, postdelim);
84
85 srand((unsigned)getpid());
86 while(1) {
87 long now;
88 unsigned s;
89
90 time(&now);
91 /* set == 1 after setjmp()
92 == 2 after SIGINT caused longjmp()
93 */
94 if(set != 2)
95 strncpy(localmsg, ctime(&now), MSG_SZ-1);
96 if(!set) {
97 setjmp(bef_put_que);
98 set++;
99 }
100 if(put_que()==QUE_FULL){
101 printf("%s: queue full\n", argv[0]);
102 /* sleep - expecting some consumption */
103 sleep(10);
104 continue;
105 }
106
107 /* if put of "DELIM" was successful break out of while */
108 if(set==2)
109 break; /* only if SIGINT */
110
111 /* sleep a random amount between 1-6 */
112 s=(unsigned)rand()%6 + 1;
113 #ifdef DEBUG
114 printf("producer:sleep %d seconds\n", s);
115 #endif
116 sleep(s);
117 }
118
119 /* since parent/child relation,
120 a wait() for consumer could have been done
121 */
122 while(1) {
123 /* possibly poll for consumer to shmdt() */
124 shmctl(shmid, IPC_STAT, &shmstat);
125 if(shmstat.shm_nattch == 1)
126 break;
127 else
128 sleep(1);
129 }
130
131 wrap_up(0);
132
133 }
134
135 static int put_que(void)
136 {
137 /* add item to tail of queue.
138 item produced will be ctime() output.
139 */
140 int rtn_code;
141 void (*action)();
142
143 action = signal(SIGINT, SIG_IGN);
144 semop(semid, &lock, 1);
145
146 #ifdef DEBUG
147 print_que(q_shm, "producer about to put onto tail");
148 #endif
149 q_shm->tail = ++q_shm->tail % QUE_SZ;
150 if(q_shm->tail == q_shm->head){
151 rtn_code = QUE_FULL; /* queue full */
152 /* reset for a retry */
153 q_shm->tail = --q_shm->tail % QUE_SZ;
154 }
155 else {
156 strncpy(q_shm->msg[q_shm->tail], localmsg, MSG_SZ-1);
157 rtn_code = PUT_SUCCESS;
158 }
159 semop(semid, &unlock, 1);
160 signal(SIGINT, action);
161 return(rtn_code);
162 }
163
164 static void wrap_up(int exit_code)
165 {
166 semctl(semid, 0, IPC_RMID ,0);
167 shmdt(q_shm);
168 shmctl(shmid, IPC_RMID, NULL);
169 exit(exit_code);
170 }
171
172 static void postdelim(int sig)
173 {
174 strcpy(localmsg, "DELIM\n");
175 longjmp(bef_put_que, 1);
176 }
177
178 static void rpterror(char *string)
179 {
180 char errline[50];
181
182 sprintf(errline,"%s %s", string, pname);
183 perror(errline);
184 }
185
186 #ifdef DEBUG
187 static void print_que(struct CIRC_QUE *qptr, char *label)
188 {
189 static int k;
190 int i;
191
192 printf("%s - %d call\n", label, ++k);
193 printf("head=%d tail=%d\n",qptr->head,qptr->tail);
194
195 for(i=0; i<QUE_SZ; i++)
196 printf("msg[%d]=%s\n", i, qptr->msg[i]);
197 }
198 #endif
ðïôòåâéôåìø, þéôáàýéê éú ëïìøãå÷ïê ïþåòåäé, cons_qshm.c :
1 /* consumer program:
2 a circular queue of fixed size items is implemented in shared
3 memory. producer puts items at tail of queue.
4 consumer gets items from head of queue.
5 DELIMITER entry indicates to consumer that producer is done.
6 DELIMITER produced upon receipt of SIGINT signal.
7 semaphore used to ensure mutually exclusive queue update.
8 */
9 #include <sys/types.h>
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/ipc.h>
14 #include <sys/sem.h>
15 #include <sys/shm.h>
16 #include <signal.h>
17 #include <string.h>
18 #define QUE_SZ 5
19 #define MSG_SZ 30
20 struct CIRC_QUE {
21 int head;
22 int tail;
23 char msg[QUE_SZ][MSG_SZ];
24 };
25 static struct CIRC_QUE *q_shm;
26 #define GET_SUCCESS 0
27 #define QUE_EMPTY -2
28 #define DELIM_STR -1
29 static char localmsg[MSG_SZ], *pname;
30 static int semid, shmid;
31 static struct sembuf lock = { 0, -1, 0};
32 static struct sembuf unlock = { 0, 1, 0};
33 static void rpterror(char *);
34 #ifdef DEBUG
35 static void print_que(struct CIRC_QUE *, char *);
36 #endif
37 static int get_que(void);
38
39 main(int argc, char *argv[])
40 {
41
42 pname = argv[0];
43
44 sigset(SIGINT, SIG_IGN);
45
46 setbuf(stdout, NULL);
47
48 semid = atoi(argv[1]);
49
50 shmid = atoi(argv[2]);
51
52
53 q_shm=shmat(shmid, 0, 0);
54
55 srand((unsigned)getpid());
56
57 while(1) {
58 int get_stat;
59 unsigned s;
60
61 get_stat = get_que();
62 switch(get_stat) {
63 case GET_SUCCESS:
64 case DELIM_STR:
65 /* no \n, because all entries have newline*/
66 printf("%s:received=%s",argv[0], localmsg);
67 /* sleep a random amount between 1-6 */
68 s=(unsigned)rand()%6 + 1;
69 #ifdef DEBUG
70 printf("producer:sleep %d seconds\n",s);
71 #endif
72 sleep(s);
73 break;
74 case QUE_EMPTY:
75 printf("%s: queue empty\n", argv[0]);
76 sleep(10);
77 continue;
78 }
79
80 if(get_stat == DELIM_STR)
81 break;
82 }
83
84 shmdt(q_shm);
85 }
86
87 static int get_que(void)
88 {
89 int rtn_code;;
90 /* retrieve next item from head of queue */
91
92 if(semop(semid, &lock, 1) == -1){
93 rpterror("semop lock");
94 exit(1);
95 }
96 #ifdef DEBUG
97 print_que(q_shm,"consumer about to get from head");
98 #endif
99
100 if(q_shm->head == q_shm->tail)
101 rtn_code = QUE_EMPTY;
102 else {
103 q_shm->head = ++q_shm->head % QUE_SZ;
104 strncpy(localmsg, q_shm-> msg[q_shm->head], MSG_SZ-1);
105 if(!strcmp(localmsg, "DELIM\n"))
106 rtn_code = DELIM_STR;
107 else
108 rtn_code = GET_SUCCESS;
109 }
110 if(semop(semid, &unlock, 1) == -1) {
111 rpterror("semop unlock");
112 exit(2);
113 }
114 return(rtn_code);
115 }
116
117 static void rpterror(char *string)
118 {
119 char errline[50];
120 sprintf(errline,"%s %s", string, pname);
121 perror(errline);
122 }
123
124 #ifdef DEBUG
125 static void print_que(struct CIRC_QUE *qptr, char *label)
126 {
127 static int k;
128 int i;
129 printf("%s %d call\n", label, ++k);
130 printf("head=%d tail=%d\n",qptr->head,qptr->tail);
131
132 for(i=0; i<QUE_SZ; i++)
133 printf("msg[%d]=%s\n", i, qptr->msg[i]);
134 }
135 #endif
÷ùúï÷:
$ prod_qshm
q_consumer: received=Wed Jan 22 12:10:53 1986
q_consumer: queue empty
q_consumer: received=Wed Jan 22 12:10:57 1986
<DELETE>
úÁÍÅÞÁÎÉÅ: SIGINT - ÜÔÏ ÕÓÌÏ×ÉÅ ÏÇÒÁÎÉÞÅÎÉÑ
q_consumer: received=Wed Jan 22 12:11:01 1986
q_consumer: received=Wed Jan 22 12:11:05 1986
q_consumer: received=DELIM