基于Linux进程共享内存&进程共享mutex实现的订票模型

本文档详细介绍了如何使用`pthread`库在Server进程中创建共享内存、信号量和互斥锁,以及在Client进程中进行跨进程同步操作。重点讨论了进程共享属性和健壮属性的设置,以及`pthread_mutex_consistent`函数在处理EOWNERDEAD时的作用。通过实例展示了如何将MUTEX分配在进程共享内存中实现进程间的同步协调。
摘要由CSDN通过智能技术生成

原理:

Server进程:

#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <pthread.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>


#define PERR(msg)  do { perror(msg); exit(-1); } while(0)
#define PPERR(err,msg) do { err=errno; perror(msg); exit(-1); } while(0)

struct ticket
{
    int remain;
    pthread_mutex_t lock;
};

// 打印mutex的 进程共享属性
void printshared(pthread_mutexattr_t *attr)
{
    int err,shared;

    err = pthread_mutexattr_getpshared(attr,&shared);

    if (err != 0) PPERR(err,"pthread_mutexattr_getshared");
    if (shared == PTHREAD_PROCESS_PRIVATE)
        puts("shared = PTHREAD_PROCESS_PRIVATE");
    else if (shared == PTHREAD_PROCESS_SHARED)
        puts("shared = PTHREAD_PROCESS_SHARED");
    else 
        puts("shared = ???");

    return;
}

// 打印mutex的 健壮属性
void printrobust(pthread_mutexattr_t *attr)
{
    int err,robust;
    err = pthread_mutexattr_getrobust(attr,&robust);

    if (err != 0) PPERR(err,"pthread_mutexattr_getrobust");
    if (robust == PTHREAD_MUTEX_STALLED)
        puts("robust = PTHREAD_MUTEX_STALLED");
    else if (robust == PTHREAD_MUTEX_ROBUST)
        puts("robust = PTHREAD_MUTEX_ROBUST");
    else 
        puts("robust = ???");
    
    return;
}

int main(int argc, char **argv)
{ 
    int err,shared;
    int done = 0;
    // genernate key_t type 0x5axxxxxx
    key_t key = ftok(".",0x5a);

    int id = shmget(key,getpagesize(),IPC_CREAT | IPC_EXCL | 0666);
    if (id < 0) PERR("shmget");

    struct ticket *t = (struct ticket *)shmat(id,NULL,0);
    if (t == (void *)-1) PERR("shmat");

    t->remain = 10;

    pthread_mutexattr_t mutexattr;
    err = pthread_mutexattr_init(&mutexattr);
    if (err != 0) PPERR(err,"pthread_mutexattr_init");

    printshared(&mutexattr);
    printrobust(&mutexattr);

    shared = PTHREAD_PROCESS_SHARED;
    err = pthread_mutexattr_setpshared(&mutexattr,shared);
    if (err != 0) PPERR(err,"pthread_mutexattr_setpshared");

    err = pthread_mutexattr_setrobust(&mutexattr,PTHREAD_MUTEX_ROBUST);
    if (err != 0) PPERR(err,"pthread_mutexattr_setrobust");

    puts("modify attribute ----------------------");
    printshared(&mutexattr);
    printrobust(&mutexattr);

    pthread_mutex_init(&t->lock,&mutexattr);

    while(!done)
    {
        sleep(1);
	printf("server remain %d.\n", t->remain);
    }

    err = pthread_mutex_destroy(&t->lock);
    if (err != 0) PPERR(err,"pthread_mutex_destroy");

    err = pthread_mutexattr_destroy(&mutexattr);
    if (err != 0) PPERR(err,"pthread_mutexattr_destroy");


    err = shmdt((void *)t);
    if (err != 0) PERR("shmdt");

    err = shmctl(id,IPC_RMID,NULL);
    if (err != 0) PERR("shmctl");

    return 0;
}

client1.c

#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

#define PERR(msg) do { perror(msg); exit(-1); } while(0) 
#define PPERR(err,msg) do { err=errno; perror(msg); exit(-1); } while(0)

struct ticket 
{
    int remain;
    pthread_mutex_t lock;
};

int main(int argc,char *argv[])
{
    key_t key = ftok(".",0x5a);

    if (argc < 2)
    {
        printf("Usage: %s <name>\n",argv[0]);
        exit(-1);
    } 

    char *name = argv[1];
    int err,shared,flag = 1;
    int id = shmget(key,0,0);
    if (id < 0) PERR("shmget");

    struct ticket *t = (struct ticket*)shmat(id,NULL,0);

    if (t == (void *)-1) PERR("shmat");

    while (flag)
    {
        err = pthread_mutex_lock(&t->lock);
        // 需要恢复的成功
        if (err == EOWNERDEAD)
        {
            puts("EOWNERDEAD");
	    // 拥有互斥锁的进程终止后,互斥量就变成inconsistent(不一致性)
            // 恢复锁的一致性,此时进程还是获得锁的状态
	    err = pthread_mutex_consistent(&t->lock);
	    if (err != 0)
            {
                printf("consistent error\n");
                exit(-1);
            }
        }
	// 失败
	else if (err == ENOTRECOVERABLE)
        {
            puts("ENOTRECOVERABLE");
        } 

	// 不需要恢复的成功
	int remain = t->remain;
	if (remain > 0)
        {
            sleep(1);
            --remain;
            t->remain = remain;
            printf("%s buy a ticket\n",name);
            sleep(3);
        } else 
             flag = 0;
        pthread_mutex_unlock(&t->lock);
        sleep(2);
    }
    err = shmdt((void *)t);
    if (err != 0) PERR("shmdt");

    return 0;
}

client2.c

#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>

#define PERR(msg) do { perror(msg); exit(-1); } while(0) 
#define PPERR(err,msg) do { err=errno; perror(msg); exit(-1); } while(0)

struct ticket 
{
    int remain;
    pthread_mutex_t lock;
};

int main(int argc,char *argv[])
{
    key_t key = ftok(".",0x5a);

    if (argc < 2)
    {
        printf("Usage: %s <name>\n",argv[0]);
        exit(-1);
    } 

    char *name = argv[1];
    int err,shared,flag = 1;
    int id = shmget(key,0,0);
    if (id < 0) PERR("shmget");

    struct ticket *t = (struct ticket*)shmat(id,NULL,0);

    if (t == (void *)-1) PERR("shmat");

    while (flag)
    {
        err = pthread_mutex_lock(&t->lock);
        // 需要恢复的成功
        if (err == EOWNERDEAD)
        {
            puts("EOWNERDEAD");
	    // 拥有互斥锁的进程终止后,互斥量就变成inconsistent(不一致性)
            // 恢复锁的一致性,此时进程还是获得锁的状态
	    err = pthread_mutex_consistent(&t->lock);
	    if (err != 0)
            {
                printf("consistent error\n");
                exit(-1);
            }
        }
	// 失败
	else if (err == ENOTRECOVERABLE)
        {
            puts("ENOTRECOVERABLE");
        } 

	// 不需要恢复的成功
	int remain = t->remain;
	if (remain > 0)
        {
            sleep(1);
            --remain;
            t->remain = remain;
            printf("%s buy a ticket\n",name);
            sleep(3);
        } else 
             flag = 0;
        pthread_mutex_unlock(&t->lock);
        sleep(2);
    }
    err = shmdt((void *)t);
    if (err != 0) PERR("shmdt");

    return 0;
}

Makefile:

all:
	gcc -g server.c -o server -lpthread
	gcc -g client1.c -o client1 -lpthread
	gcc -g client2.c -o client2 -lpthread
clean:
	rm -fr server client1 client2

测试:

用到的几个pthread函数:

ftok的实现:

mutex共享标志:

pthread_mutex_t定义的第一个四字节成员的bit 7用来标志当前的mutex是进程共享还是进程私有的。0表示私有,1表示共享。

通过下面两个函数设置:

总结

所以,MUTEX跨进程同步,就是将MUTEX分配在进程共享内存中,在去做同步。

参考资料

musl libc库的编译以及malloc & mutex实现简析-CSDN博客

最好的共享内存(Linux共享内存最透彻的一篇) - 知乎


结束!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值