[<<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