原理:

基于Linux共享内存实现的订票系统_不一致性

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

测试:

基于Linux共享内存实现的订票系统_#define_02

基于Linux共享内存实现的订票系统_#define_03

用到的几个pthread函数:

基于Linux共享内存实现的订票系统_#define_04

基于Linux共享内存实现的订票系统_不一致性_05

基于Linux共享内存实现的订票系统_不一致性_06

ftok的实现:

基于Linux共享内存实现的订票系统_#include_07


结束!