linux下实现进程同步

网上的大部分教程讲的都是线程同步,却很少有关于进程同步的博客,但其实线程同步与进程同步还是有些许差别的,故写此博客加以说明.

知识点

1.linux semaphore

头文件#include
编译注意事项:注意关联pthread, 即在编译命令之后加上-lthread
主要使用了linux的信号量及相应函数.

  • int sem_init(sem_t *sem, int pshared, unsigned int value);//初始化信号量
    主要注意第二个与第三个参数,pshared指明信号量是否进程共享,如果pshared为0,则只能在同一个进程中使用,如果不等于0,则能在进程之间共享,但需要使用共享内存的方式共享信号量(详情见下图官方文档说明)value指明能够同时运行的线程或者进程数量,wait会使其减1, post会使其加1
    linux下实现进程同步_第1张图片
  • int sem_wait(sem_t *sem);//如果没有信号,则进程或者线程阻塞,相当于p操作
  • int sem_post(sem_t *sem);//释放信号量,相当v操作
  • int sem_destroy(sem_t *sem);//销毁信号量

2.共享内存

在实现线程同步时并不需要共享内存,因为只要信号量是一个全局变量,线程之间就能够共享该信号量,但进程与线程有所不同.在创建父子进程时,子进程会将父进程中的变量拷贝一份,所以父子进程在使用同一变量时互不影响,因为子进程只是使用变量的副本.为了实现进程同步,只能使用共享内存的方式共享信号量.

实现

实现进程同步,则需要保证一个进程必须在另一个进程之前运行,如果只使用一个信号量,无法保证两个进程的执行顺序,所以考虑使用两个信号量.大致思路如下(保证进程A先运行):

	sem_t sem1, sem2;
	  /*共享内存*/
	 /*IPC_CREAT表示在key标识的共享内存不存在时,创建共享内存*/
	int shmid1 = shmget((key_t)111, sizeof(sem_t), 0666 | IPC_CREAT);
	/*调用成功时返回一个指向共享内存第一个字节的指针*/
    void *shm1 = shmat(shmid1, 0, 0);
    sem1 = (sem_t *)shm1;
    
    int shmid2 = shmget((key_t)111, sizeof(sem_t), 0666 | IPC_CREAT);
    void *shm2 = shmat(shmid2, 0, 0);
    sem2 = (sem_t *)shm2;
    
    sem_init(&(sem1), 1, 1); 
    sem_init(&(sem2), 1, 0);
    ....
Process A:
	sem_wait(&(sem1)); //等待
	....
	sem_post(&sem2);//释放

Process B:
  sem_wait(&(sem2)); //等待
	....
	sem_post(&sem1);//释放

代码

#include 
#include 
#include 
#include 
#include 
#include 

#define N 100

struct shareData
{
    sem_t sem1;
    sem_t sem2; //2个信号量实现同步操作,需要link pthread
    int arr[N];
};
int main()
{
    int pid;

    /*IPC_CREAT表示在key标识的共享内存不存在时,创建共享内存*/
    int shmid = shmget((key_t)1234, sizeof(struct shareData), 0666 | IPC_CREAT);
    /*调用成功时返回一个指向共享内存第一个字节的指针*/
    void *shm = shmat(shmid, 0, 0);
    struct shareData *shareData = (struct shareData *)shm;
    /*初始化信号量,第一个1表示信号量可以在进程之间共享,第二个1表示只能同时执行一个进程*/
    sem_init(&(shareData->sem1), 1, 1); 
    sem_init(&(shareData->sem2), 1, 0);
    //创建进程
    pid = fork();
    if (pid > 0)
    {
        sem_wait(&(shareData->sem1)); //等待
        for (int i = 0; i < N; i++)
        {
            shareData->arr[i] = i + 1; //父进程写入数据
            printf("Parent Input:%d\n", shareData->arr[i]);
        }
        sem_post(&(shareData->sem2)); //释放
    }
    else if (pid == 0)
    {
        sem_wait(&(shareData->sem2));
        for (int i = 0; i < N; i++)
        {
            printf("Output:%d\n", shareData->arr[i]); //子进程读出数据
        }
        sem_post(&(shareData->sem1));
    }
    else if (pid < 0)
    {
        return -1;
    }
    sem_destroy(&(shareData->sem1));
    sem_destroy(&(shareData->sem2)); //删除信号量
    shmctl(shmid, IPC_RMID, 0);      //删除共享内存
    return 0;
}

你可能感兴趣的:(操作系统原理)