您的位置:首页 > 运维架构 > Linux

进程间互斥

2016-04-07 16:53 645 查看
简单做一下进程间互斥的实现方法,如有不足或错误之处还望各位道友指正!

一、信号量

信号量简单的来说就是一个计数器,当一个进程尝试去读取一个共享资源之前,进程先测试相应的信号量,若信号量大于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);

    

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux ipc