/* * sem-mutex.c - demonstrates the usage of a semaphore as a mutex that * that synchronizes accesses of multiple processes * to a file. */ #include /* standard I/O routines. */ #include /* rand() and srand() functions */ #include /* fork(), etc. */ #include /* nanosleep(), etc. */ #include /* various type definitions. */ #include /* general SysV IPC structures */ #include /* semaphore functions and structs. */ #include /* wait(), etc. */ #define NUM_PROCS 5 /* number of processes to launch. */ #define SEM_ID 250 /* ID for the semaphore. */ #define FILE_NAME "sem_mutex" /* name of file to manipulate */ #if defined(__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED) /* union semun is defined by including */ #else /* according to X/OPEN we have to define it ourselves */ union semun { int val; /* value for SETVAL */ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */ unsigned short int *array; /* array for GETALL, SETALL */ struct seminfo *__buf; /* buffer for IPC_INFO */ }; #endif /* this function updates the contents of the file with the given path name. */ void update_file(int sem_set_id, char* file_path, int number) { /* structure for semaphore operations. */ struct sembuf sem_op; FILE* file; /* wait on the semaphore, unless it's value is non-negative. */ sem_op.sem_num = 0; sem_op.sem_op = -1; /* <-- Comment 1 */ sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); /* Comment 2 */ /* we "locked" the semaphore, and are assured exclusive access to file. */ /* manipulate the file in some way. for example, write a number into it. */ file = fopen(file_path, "w"); if (file) { fprintf(file, "%d\n", number); printf("%d\n", number); fclose(file); } /* finally, signal the semaphore - increase its value by one. */ sem_op.sem_num = 0; sem_op.sem_op = 1; /* <-- Comment 3 */ sem_op.sem_flg = 0; semop(sem_set_id, &sem_op, 1); } /* this function calls "file_update" several times in a row, */ /* and waiting a little time between each two calls, in order */ /* to allow other processes time to operate. */ void do_child_loop(int sem_set_id, char* file_name) { pid_t pid = getpid(); int i, j; for (i=0; i<3; i++) { update_file(sem_set_id, file_name, pid); for (j=0; j<400000; j++) ; } } /* finally, the main() function. */ int main() { int sem_set_id; /* ID of the semaphore set. */ union semun sem_val; /* semaphore value, for semctl(). */ int child_pid; /* PID of our child process. */ int i; /* counter for loop operation. */ int rc; /* return value of system calls. */ /* create a semaphore set with ID 250, with one semaphore */ /* in it, with access only to the owner. */ sem_set_id = semget(SEM_ID, 1, IPC_CREAT | 0600); if (sem_set_id == -1) { perror("main: semget"); exit(1); } /* intialize the first (and single) semaphore in our set to '1'. */ sem_val.val = 1; rc = semctl(sem_set_id, 0, SETVAL, sem_val); if (rc == -1) { perror("main: semctl"); exit(1); } /* create a set of child processes that will compete on the semaphore */ for (i=0; i