进程间互斥

来源:互联网 发布:php 接口文档管理系统 编辑:程序博客网 时间:2024/05/21 15:51

简单做一下进程间互斥的实现方法,如有不足或错误之处还望各位道友指正!

一、信号量

信号量简单的来说就是一个计数器,当一个进程尝试去读取一个共享资源之前,进程先测试相应的信号量,若信号量大于0,则该进程可以使用共享资源并且将信号量减去sem_op(使用完后将信号量加sem_op),若信号量等于0,则进程进入休眠,等待信号量大于0(即其他进程使用完该资源),以此实现多进程对共享资源的同步访问。

在linux中,信号量实现的函数:

int semget(key_t key, int nsems, int flag);

int semctl(int semid, int semnum, int cmd, /* union semun arg*/);

int semop(int semid, struct sembuf semoption[], size_t nops);

semget()函数创建一个新的信号量集合或获取一个已经存在的信号量集合,具体参数及实现就不说了,自己去man一下就行了

semctl()函数实现对信号集中的信号进行操作,基本就是初始化设置(比如设置信号量值)、获取先好量的各种参数,删除信号量集合

semop()函数实现在操作共享资源前的检查信号量的值,大于0则获得该共享资源的操作权并将信号减sem_op,或使用完共享资源后将信号量加sem_op

实例:

实例中子进程与父进程都向屏幕打印20个字母,采用信号量使之能够按我们预想的哪像打印,而不会打印乱序

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int
main(int argc, char** argv)
{
    key_t key;
    pid_t pid;
    int semid;
    struct sembuf semoption[1];
    union semun
    {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    }s;
    
    key=ftok("/tmp/1234", 'a');
    semid=semget(key, 1, IPC_CREAT | 0666);
    s.val=1;
    semctl(semid, 0, SETVAL, s);
    semoption[0].sem_num=0;
    semoption[0].sem_op=-1;
    semoption[0].sem_flg=SEM_UNDO;

    if( (pid=fork())==0)
    {
        semid=semget(key, 0, IPC_CREAT | 0666);
        semop(semid, semoption, 1);
        int i;
        for( i=0; i<20; i++)
            printf("A-\n");
        semoption[0].sem_op=1;
        semop(semid, semoption, 1);
        
        return(0);
    }
    semop(semid, semoption, 1);
    int i=0;
    for( ; i<20; i++)
        printf("B-\n");
    semoption[0].sem_op=1;
    semop(semid, semoption, 1);

    sleep(1);
    semctl(semid, 0, IPC_RMID);
    
}

二、互斥量

互斥量利用了pthread_mutex_t支持进程间共享的特性,将互斥量设置PTHREAD_PROCESS_SHARED,但是好要共享内存的配合,将互斥量放置于共享内存,而后多进程在读取共享资源前将检查mutex互斥量,如同线程斥量一般。

linux中实现所调用的函数:

int pthread_mutexattr_getpshared(const pthread_mutexattr_t *restrict attr, int *restrict pshared);//mutxeattr设置PTHREAD_PROCESS_SHARED

int pthread_mutex_init(const pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *resrict attr);//初始话互斥量mutex

int shmget(key_t key, size_t size, int flag);//创建共享存储标识或则获取共享存储标识

int shmctl(int shmid, int cmd, struct shmid_ds *buf);//控制共享存储段,获取存储段信息(IPC_STAT)、设置存储段信息(IPC_SET)、删除存储段(IPC_RMID)

int shmat(int shmid, const void *addr, int flag);// 将共享存储段链接到进程的地址上(类似于mmap,不过mmap链接的是命名的文件而shmat映射的是匿名内存)

int shmdt(const void *addr);//将共享存储从进程上断开分离

实例:

此实例中共享存储段中放置了互斥来量和一个int整数用来测试,进程先lock互斥量后将操作整数而后unlock

#include <stdio.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <stdlib.h>
#include <sys/shm.h>

int *sum=NULL;

int
main(int argc, char** argv)
{
    key_t key;
    int shmid, size=sizeof(pthread_mutex_t)+sizeof(int);
    void *pmen;
    pid_t pid;
    pid_t mypid;

    pthread_mutex_t *pthmutex;
    mypid=getpid();

    key=ftok("/tmp/1.c", 'b');
    if( key==-1)
    {
        printf("ftok error\n");
        return(-1);
    }
    shmid=shmget(key, size, IPC_CREAT | IPC_EXCL | 0666);
    if( shmid==-1)
    {
        printf("shmget error\n");
        return(-1);
    }
    pthmutex=(pthread_mutex_t*)shmat(shmid, 0, 0);
    pthread_mutexattr_t pthattr;
    pthread_mutexattr_setpshared(&pthattr, PTHREAD_PROCESS_SHARED);
    pthread_mutex_init(pthmutex, &pthattr);    
    sum=(int*)((void*)pthmutex+sizeof(pthread_mutex_t));
    *sum=0;

    if( (pid=fork())==0)
    {
        int cshmid;
        void *men;
        int *sum;
        pthread_mutex_t *pthmutex;
        cshmid=shmget(key, size, IPC_CREAT | 0666);
        men=shmat(cshmid, 0, 0);
        pthmutex=(pthread_mutex_t *)men;

        pthread_mutex_lock(pthmutex);
        int i;
        sum=(int*)((void*)pthmutex+sizeof(pthread_mutex_t));
        printf("first sum=%d\n", *sum);
        for( i=0; i<50; i++)
            (*sum)++;
        printf("sum=%d\n", *sum);
        pthread_mutex_unlock(pthmutex);
        exit(0);
    }

    pthread_mutex_lock(pthmutex);
    printf("second sum=%d\n", *sum);
    int j;
    for( j=0; j<50; j++)
        (*sum)++;
    printf("sum=%d\n", *sum);
    pthread_mutex_unlock(pthmutex);

    shmctl(shmid, IPC_RMID, NULL);
    
}
0 0