1. 使用posix有名信號量進(jìn)行同步
有名信號量既可用于線程間的同步,又可用于進(jìn)程間的同步。
兩個進(jìn)程,對同一個共享內(nèi)存讀寫,可利用有名信號量來進(jìn)行同步。一個進(jìn)程寫,另一個進(jìn)程讀,利用兩個有名信號量semr, semw。semr信號量控制能否讀,初始化為0。 semw信號量控制能否寫,初始為1。
示例代碼如下:
//讀共享內(nèi)存
#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;
}
//寫共享內(nèi)存
#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;
}
注意:編譯上面的代碼需要鏈接動態(tài)庫-lpthread
2. 使用posix無名信號量進(jìn)行同步
POSIX無名信號量是基于內(nèi)存的信號量,可以用于線程間同步也可以用于進(jìn)程間同步。若實現(xiàn)進(jìn)程間同步,需要在共享內(nèi)存中來創(chuàng)建無名信號量。
因此,共享內(nèi)存需要定義以下的結(jié)構(gòu)體:
typedef struct
{
sem_t semr;
sem_t semw;
char buf[MAXSIZE];
}SHM;
3. 使用system V的信號燈實現(xiàn)同步
System V的信號燈是一個或者多個信號燈的一個集合。其中的每一個都是單獨的計數(shù)信號燈。而Posix信號燈指的是單個計數(shù)信號燈。
System V 信號燈由內(nèi)核維護(hù),主要函數(shù)semget,semop,semctl 。
一個進(jìn)程寫,另一個進(jìn)程讀,信號燈集中有兩個信號燈,下標(biāo)0代表能否讀,初始化為0。 下標(biāo)1代表能否寫,初始為1。
示例代碼如下:
//進(jìn)程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;
}
//進(jìn)程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. 使用信號實現(xiàn)共享內(nèi)存的同步
其實就是使用kill和signal發(fā)送信號來實現(xiàn),這里不再實現(xiàn)。