//------------------------------------------------------------------- // lottery.cpp // // This program acts as a lottery-number server, using a shared // memory-segment to store a randomly generated 4-digit number. // A client program (named 'gambler.cpp') may access our server // to determine if a 4-digit 'bet' typed in by its user has won // or lost. The winning number is valid for only five seconds. // // This client and server program-pair provides an illustration // of the classic reader and writer problem, and shows how UNIX // semaphores may be used to appropriately synchronize accesses // to the shared memory-segment. It was inspired by an example // from "Understanding UNIX/Linux Programming," by Bruce Molay. // // programmer: ALLAN CRUSE // written on: 13 OCT 2004 //------------------------------------------------------------------- #include // for printf(), perror() #include // for rand(), exit() #include // for sleep() #include // for signal() #include // for strncpy() #include // for shmget(), shmctl(), semat(), etc #include // for semget(), semctl(), semop(), etc #include "myshmsem.h" // for MY_MEM_KEY, MY_SEM_KEY, MEM_SIZE int semset_id; // holds handle to the semaphore set int shmseg_id; // holds handle to the shared memory void *shm_buffer; // our pointer to the memory-segment int done = 0; // flag is set by termination signal void upon_signal( int signum ) { done = 1; } // for SIGINT void cleanup( int signo ) { semctl( semset_id, 0, IPC_RMID, NULL ); shmctl( shmseg_id, IPC_RMID, NULL ); } void wait_and_lock( int semset_id ) { struct sembuf actions[ 2 ]; // wait for 0 on n_readers actions[0].sem_num = 0; actions[0].sem_flg = SEM_UNDO; actions[0].sem_op = 0; // then increment n_writers actions[1].sem_num = 1; actions[1].sem_flg = SEM_UNDO; actions[1].sem_op = +1; if ( semop( semset_id, actions, 2 ) < 0 ) { perror( "semop" ); cleanup(0); exit(1); } } void release_lock( int semset_id ) { struct sembuf actions[1]; // decrement n_writers actions[0].sem_num = 1; actions[0].sem_flg = SEM_UNDO; actions[0].sem_op = -1; if ( semop( semset_id, actions, 1 ) < 0 ) { perror( "semop" ); cleanup(0); exit(1); } } int main( int argc, char **argv ) { // create a shared memory segment shmseg_id = shmget( MY_MEM_KEY, MEM_SIZE, (0666|IPC_CREAT) ); if ( shmseg_id < 0 ) { perror( "shmget" ); exit(1); } // attach to it and get a pointer to where it resides shm_buffer = shmat( shmseg_id, NULL, 0 ); printf( "shm_buffer=%p \n", shm_buffer ); // create a semaphore-set with two semaphores semset_id = semget( MY_SEM_KEY, 2, (0666|IPC_CREAT|IPC_EXCL) ); if ( semset_id < 0 ) { perror( "semget" ); exit(1); } // set both of the semaphore counters to zero union semun initval; initval.val = 0; if ( semctl( semset_id, 0, SETVAL, initval ) < 0 ) { perror( "semctl" ); cleanup(0); exit(1); } if ( semctl( semset_id, 1, SETVAL, initval ) < 0 ) { perror( "semctl" ); cleanup(0); exit(1); } // install our signal-handler signal( SIGINT, upon_signal ); while ( !done ) { char winner[ 5 ] = {0}; for ( int i = 0; i < 4; i++) winner[i] = (rand()%10)|'0'; wait_and_lock( semset_id ); strncpy( (char*)shm_buffer, winner, 4 ); printf( "%s\n", shm_buffer ); sleep( 4 ); release_lock( semset_id ); sleep( 1 ); } cleanup(0); }