struct semid_ds { struct ipc_perm sem_perm; unsigned short sem_nsems; time_t sem_otime; time_t sem_ctime; . . . };每个 信号量用一个无名结构表示:
struct { unsigned short semval; //信号值 pid_t sempid; unsigned short semncnt; //等待信号量值大于目前信号量值的进程个数 unsigned short semzcnt; //等待信号量值为0进程个数 . . . };获取共享资源:
union semun { int val; //设置无名结构中的信号值(资源个数,后面会因为semop的sem_op而变化) struct semid_ds *buf; //取或设置semid_ds结构 unsigned short *array; //信号量值数组 };int semop( int semid, struct sembuf semoparry[], size_t nops );//自动执行信号量集合上的操作数组。
struct { unsigned short sem_num; short sem_op; short sem_flg; };
信号量例子:
#include <string.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <sys/sem.h> #include <sys/ipc.h> #include <sys/types.h> #include <unistd.h> #define PATHNAME "./a.c" #define PROJ_ID 10 union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; int main(int argc, char *argv[]) { union semun sem; const int nsems = 1; struct sembuf buf; key_t key; long int semid; int semval; if ((key = ftok(PATHNAME, PROJ_ID)) < 0) { fprintf(stderr, "ftok error: %s\n", strerror(errno)); exit(1); } if ((semid = semget(key, nsems, IPC_CREAT | IPC_EXCL)) < 0) { fprintf(stderr, "semget error: %s\n", strerror(errno)); if (errno == EEXIST) semid = semget(key, 0, 0666); else exit(1); } printf("semid is: %ld\n", semid); printf("before set semval: %d\n", semctl(semid, 0, GETVAL)); sem.val = 5; if (semctl(semid, 0, SETVAL, sem) < 0) { fprintf(stderr, "semctl error: %s\n", strerror(errno)); exit(1); } printf("after set semval: %d\n", semctl(semid, 0, GETVAL)); buf.sem_num = 0; buf.sem_op = 10; buf.sem_flg = SEM_UNDO; if (semop(semid, &buf, nsems) < 0) { fprintf(stderr, "semop error: %s\n", strerror(errno)); exit(1); } printf("after set semval: %d\n", semctl(semid, 0, GETVAL)); system("ipcs -s"); semctl(semid, 0, IPC_RMID); exit(0); }输出:
semid is: 1114113 before set semval: 0 //如果去掉semctl(semid, 0, IPC_RMID),这由于SEM_UNDO,这里恢复为5 after set semval: 5 after set semval: 15 ------ Semaphore Arrays -------- key semid owner perms nsems 0xcbc384f8 0 triplec 600 1 0x0a072c86 1114113 root 0 1 0x14072c86 65538 triplec 0 1
#include <string.h> #include <errno.h> #include <sys/sem.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #define NLOOPS 10 #define SIZE sizeof(long) #define PATHNAME "./a.c" #define PARENT 0 #define CHILD 1 union semun { int val; struct semid_ds *buf; unsigned short *array; }; static int updata( long *ptr ) { return( (*ptr)++ ); } static int sem_get(int semid, struct sembuf semarr[], unsigned short semnum) { semarr->sem_num = semnum; semarr->sem_op = -1; semarr->sem_flg = SEM_UNDO; if (semop(semid, semarr, 1) < 0) { fprintf(stderr, "get semop error: %s\n", strerror(errno)); return(1); } return(0); } static int sem_rel(int semid, struct sembuf semarr[], unsigned short semnum) { semarr->sem_num = semnum; semarr->sem_op = 1; semarr->sem_flg = SEM_UNDO; if (semop(semid, semarr, 1) < 0) { fprintf(stderr, "release semop error: %s\n", strerror(errno)); return(1); } return(0); } int main( void ) { int fd, i = 0, counter; pid_t pid; void *area; int semid; const int nsems = 2; struct sembuf semarr; union semun sem_un; key_t key; if ((key = ftok(PATHNAME, 3)) < 0) { //get key by pathname and id fprintf(stderr, "ftok error: %s\n", strerror(errno)); exit(1); } if ((semid = semget(key, nsems, IPC_CREAT)) < 0) { //get semaphore id fprintf(stderr, "semget error: %s\n", strerror(errno)); exit(1); } sem_un.val = 0; //semval=0, sem_rel can add 1 to it if ((semctl(semid, CHILD, SETVAL, sem_un)) < 0) { //resource is zero (semval = 0) fprintf(stderr, "semctl error: %s\n", strerror(errno)); exit(1); } if ((semctl(semid, PARENT, SETVAL, sem_un)) < 0) { //resource is zero (semval = 0) fprintf(stderr, "semctl error: %s\n", strerror(errno)); exit(1); } if( (fd = open("/dev/zero", O_RDWR)) < 0 ) perror( "open" ); if( (area = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED ) //create share memery perror( "mmap error" ); close( fd ); *(long *)area = 0; //just in case that area is not zero if( (pid = fork()) < 0 ) perror( "fork" ); else if( pid > 0 ) //parent { for( i=1; i < NLOOPS + 1; i+=2 ) { sem_get(semid, &semarr, PARENT); //get PARENT from child if( (counter = updata((long *)area)) != i ) { printf( "p: e %d, g %d\n", i, counter ); exit(1); } printf("p area: %ld\n", *(long *)area); sem_rel(semid, &semarr, CHILD); //release CHILD for child } } else { //child for( i=0; i < NLOOPS; i += 2 ) { if( (counter = updata((long *)area)) != i ) { printf( "c: e %d, g %d\n", i, counter ); exit(1); } printf("c area: %ld\n", *(long *)area); sem_rel(semid, &semarr, PARENT); //release PARENT for parent sem_get(semid, &semarr, CHILD); //get CHILD from parent } } exit( 0 ); }输出:
c area: 1 p area: 2 c area: 3 p area: 4 c area: 5 p area: 6 c area: 7 p area: 8 c area: 9 p area: 10
#include "sync.h" #include <errno.h> #include <stdlib.h> #include <fcntl.h> #include <sys/mman.h> #include <stdio.h> #include <string.h> #include <sys/shm.h> #define NLOOPS 10 #define SIZE sizeof(long) #define PATHNAME "./a.c" static int updata( long *ptr ) { return( (*ptr)++ ); } int main( void ) { int i = 0, counter; pid_t pid; key_t key; int shmid; void *area; key = ftok(PATHNAME, 0); if ((shmid = shmget(key, SIZE, IPC_CREAT)) < 0) { fprintf(stderr, "shmget error: %s\n", strerror(errno)); exit(1); } printf("shmid: %d\n", shmid); if ((area = shmat(shmid, NULL, 0)) == NULL) { fprintf(stderr, "shmat error: %s\n", strerror(errno)); exit(1); } printf("area: %p\n", area); *(long *)area = 0; TELL_WAIT(); if( (pid = fork()) < 0 ) perror( "fork" ); else if( pid > 0 ) { for( i=0; i < NLOOPS; i+=2 ) { if( (counter = updata((long *)area)) != i ) { printf( "p: e %d, g %d\n", i, counter ); exit(1); } printf("p area: %ld\n", *(long *)area); TELL_CHILD( pid ); WAIT_CHILD(); sleep(1); } shmdt(area); exit(0); } else { for( i=1; i < NLOOPS + 1; i += 2 ) { WAIT_PARENT(); if( (counter = updata((long *)area)) != i ) { printf( "c: e %d, g %d\n", i, counter ); exit(1); } printf("c area: %ld\n", *(long *)area); TELL_PARENT( getppid() ); sleep(1); } } shmdt(area); if (shmctl(shmid, IPC_RMID, NULL) < 0) { fprintf(stderr, "shmctl error: %s\n", strerror(errno)); exit(1); } exit( 0 ); }输出:
shmid: 7274522 area: 0x7f8f67804000 p area: 1 c area: 2 p area: 3 c area: 4 p area: 5 c area: 6 p area: 7 c area: 8 p area: 9 c area: 10shmat与mmap的区别: