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 发送信号来实现, 这里不再实现.
来源: http://www.jianshu.com/p/ee5bb8948dc0