1. 使用posix有名信号量进行同步
有名信号量既可用于线程间的同步,又可用于进程间的同步。
两个进程,对同一个共享内存读写,可利用有名信号量来进行同步。一个进程写,另一个进程读,利用两个有名信号量semr, semw。semr信号量控制能否读,初始化为0。 semw信号量控制能否写,初始为1。
示例代码如下:
//读共享内存 #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <semaphore.h> #include <stdio.h> #include <errno.h> #include <fcntl.h> typedef struct _Teacher { char name[64]; int age; }Teacher; int main() { int shmid = -1; key_t key = 0x2234; Teacher *p = NULL; sem_t *semr = NULL, *semw = NULL; semr = sem_open("sem_r", O_CREAT | O_RDWR, 0666, 0); if (semr == SEM_FAILED ) { printf("errno = %d\n", errno ); return -1; } semw = sem_open("sem_w", O_CREAT | O_RDWR, 0666, 1 ); if (semw == SEM_FAILED) { printf("errno = %d\n", errno ); return -1; } shmid = shmget(key, 0, 0 ); if ( shmid == -1 ) { printf("shmget failed\n"); perror("shmget err"); return -1; } p = (Teacher*)shmat(shmid, NULL, 0); if (p == (Teacher*)(-1)) { printf("shmat failed\n"); perror("shmat"); return -1; } while(1) { sem_wait(semr); printf("name:%s\n", p->name); printf("age:%d\n", p->age); sem_post(semw); } //shmdt(p); return 0; }
//写共享内存 #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <semaphore.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <fcntl.h> //declare O_CREAT O_RDWR typedef struct _Teacher { char name[64]; int age; }Teacher; int main() { int shmid = -1; key_t key = 0x2234; Teacher *p = NULL; int count = 0; sem_t *semr = NULL, *semw = NULL; semr = sem_open("sem_r", O_CREAT | O_RDWR, 0666, 0); if (semr == SEM_FAILED ) { printf("errno = %d\n", errno ); return -1; } semw = sem_open("sem_w", O_CREAT | O_RDWR, 0666, 1 ); if (semw == SEM_FAILED) { printf("errno = %d\n", errno ); return -1; } shmid = shmget(key, sizeof(Teacher), 0666 | IPC_CREAT ); if ( shmid == -1 ) { perror("shmget"); return -1; } p = (Teacher*)shmat(shmid, NULL, 0); if (p == (Teacher*)(-1)) { perror("shmat"); return -1; } while(1) { sem_wait(semw); //printf(">name:"); strcpy(p->name, "aaaa"); p->age = count; ++count; sem_post(semr); } return 0; }
注意:编译上面的代码需要链接动态库-lpthread
2. 使用posix无名信号量进行同步
POSIX无名信号量是基于内存的信号量,可以用于线程间同步也可以用于进程间同步。若实现进程间同步,需要在共享内存中来创建无名信号量。
因此,共享内存需要定义以下的结构体:
typedef struct { sem_t semr; sem_t semw; char buf[MAXSIZE]; }SHM;
3. 使用system V的信号灯实现同步
System V的信号灯是一个或者多个信号灯的一个集合。其中的每一个都是单独的计数信号灯。而Posix信号灯指的是单个计数信号灯。
System V 信号灯由内核维护,主要函数semget,semop,semctl 。
一个进程写,另一个进程读,信号灯集中有两个信号灯,下标0代表能否读,初始化为0。 下标1代表能否写,初始为1。
示例代码如下:
//进程A #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <sys/sem.h> #include <semaphore.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <fcntl.h> //declare O_CREAT O_RDWR int shm_id, sem_id; char* addr; void ser_exit(int signo) { semctl(sem_id, 0, IPC_RMID); semctl(sem_id, 1, IPC_RMID); shmdt(addr); shmctl(shm_id, IPC_RMID, NULL); printf("server exit ...\n"); exit(0); } union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; int main() { struct sigaction act; act.sa_handler = ser_exit; key_t shm_key = ftok("./readshm", 1); if (shm_key == -1 ) { perror("ftok error"); return -1; } int shm_id = shmget(shm_key, 1024, IPC_CREAT | IPC_EXCL | 0755); if (shm_id == -1) { perror("shmget"); return -1; } char* addr = (char*)shmat(shm_id, NULL, 0); if (addr == (char*)(-1)) { perror("shmat"); return -1; } int sem_id = semget(shm_key, 2, IPC_CREAT|IPC_EXCL|0755); if (sem_id == -1 ) { perror("semget"); return -1; } union semun init; init.val = 0; semctl(sem_id, 0, SETVAL, init); semctl(sem_id, 1, SETVAL, init); struct sembuf v = {0, 1, SEM_UNDO}; struct sembuf p = {1, -1, SEM_UNDO}; sigaction(SIGINT, &act, NULL); while(1) { printf("ser:>"); scanf("%s", addr); semop(sem_id, &v, 1); semop(sem_id, &p, 1); printf("cli:>%s\n", addr); } return 0; }
//进程B #include <sys/ipc.h> #include <sys/shm.h> #include <sys/types.h> #include <sys/sem.h> #include <semaphore.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> #include <fcntl.h> //declare O_CREAT O_RDWR union semun { int val; struct semid_ds *buf; unsigned short *array; struct seminfo *__buf; }; void cli_exit(int signo) { printf("client exit ...\n"); exit(0); } int main() { struct sigaction act; act.sa_handler = cli_exit; key_t shm_key = ftok("./readshm", 1); if (shm_key == -1 ) { perror("ftok error"); return -1; } int shm_id = shmget(shm_key, 0, 0); if (shm_id == -1) { perror("shmget"); return -1; } char* addr = (char*)shmat(shm_id, NULL, 0); if (addr == (char*)(-1)) { perror("shmat"); return -1; } int sem_id = semget(shm_key, 0, 0 ); if (sem_id == -1 ) { perror("semget"); return -1; } struct sembuf v = {1, 1, SEM_UNDO}; struct sembuf p = {0, -1, SEM_UNDO}; sigaction(SIGINT, &act, NULL); while(1) { semop(sem_id, &p, 1); printf("ser:>%s\n", addr ); printf("cli:>"); scanf("%s", addr); semop(sem_id, &v, 1); } return 0; }
4. 使用信号实现共享内存的同步
其实就是使用kill和signal发送信号来实现,这里不再实现。