分享

linux下多线程扑克游戏框架

 昵称11427297 2013-05-05
/*
* rc.c
* 文件描述:
* 1)提供了linux下“升级”(北方常见的一种扑克玩法)游戏的框架。
* 2)库:glibc2.15;编译环境:gcc4.7.2;内核:3.8.4
*              3)  编译:gcc -pthread -DDEBUG -o rc rc.c
* 作者:漂流骑士
* 发布时间:2013.4.3
*/
#include <stdlib.h>
#include <stdio.h>
#include <pwd.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <pthread.h>
#include <setjmp.h>
#include <termios.h>

#define PLAYERCOUNT 4
#define PLAYED_CARDS_NO 4
#define PLAYING_WAITING 10
#define BUFFER_RECV 128

#ifdef DEBUG
#define DPRINTF(s) printf s
#else
#define DPRINTF(s)
#endif
#define ERR_HANDLER(s) {perror s; exit(-1);}

typedef enum
{
STAGE_HANPAI = 0,
STAGE_CALC
}stage_t;

typedef struct barrier_hanpai_tag
{
int mailbox_hanpai; /*空闲标志。0为空闲,1为繁忙*/
pthread_mutex_t m_hanpai[2]; /*m_hanpai[0]与同步信号配套的互斥量
m_hanpai[1]确保喊牌期间运行控制线程(RC线程)首先执行*/
pthread_cond_t c_hanpai_P2RC; /*喊牌期间,玩家发给运行控制线程的同步信号*/
}barrier_hanpai_t, *barrier_hanpai_p;

typedef struct barrier_calc_tag
{
int mailbox_calc; /*空闲标志。0为空闲,1为繁忙*/
pthread_mutex_t m_calc[2]; /*m_calc[0]与同步信号配套的互斥量
m_calc[1]确保出牌(计算)期间运行控制线程首先执行*/
pthread_cond_t c_calc_P2RC; /*计算期间,玩家发给运行控制线程的同步信号*/
}barrier_calc_t, *barrier_calc_p;

typedef struct barrier_tag
{
int sqno; /*玩家序号*/
pthread_t player[PLAYERCOUNT];
pthread_mutex_t m_global; /*确保运行控制线程每局均能首先运行*/
pthread_mutex_t m_interplayer; /*玩家线程间的互斥*/
pthread_cond_t c_RC2P; /*喊牌、计算期间,RC线程发给玩家线程的信号*/
pthread_cond_t c_ready_P2RC; /*每局牌开始时的同步*/
struct barrier_hanpai_tag barrier_hanpai;
struct barrier_calc_tag barrier_calc;
}barrier_t, *barrier_p;

typedef void (*sighandler_t)(int);

sigset_t signal_set;
int repeatflag_hanpai = 1, repeatflag_calc = 1, quitflag = 0;
int player_hanpai_decision = 0xca;
char player_status_play = 0;
char player_status_hanpai = 0;
sigjmp_buf jmpbuf_hanpai[4];
sigjmp_buf jmpbuf_calc[4];

void hanpai(int counter, int sqno, barrier_p mybarrier)
{
char buffer[10];

/*若为第二次喊牌则采取激进策略*/
if(counter >= 1) {
DPRINTF(("采取激进策略\n"));
sleep(2);
} else
sleep(1);
if(sqno == 0) {
tcflush(fileno(stdin), TCIFLUSH);
read(fileno(stdin), buffer, 10);
}

pthread_mutex_lock(&mybarrier->m_interplayer);
player_status_hanpai |= 1 << sqno;
//player_hanpai_decision = 0xaa; /* 0x00:没资格;0x11:喊牌; 0x10:有资格但不喊 */
pthread_mutex_unlock(&mybarrier->m_interplayer);
}

int calculate(int sqno, barrier_p mybarrier)
{
char buffer[10];

DPRINTF(("玩家 %d 正在计算...\n", sqno));
sleep(1);
if(sqno == 1) {
tcflush(fileno(stdin), TCIFLUSH);
read(fileno(stdin), buffer, 10);
}
if(sqno == 3) {
tcflush(fileno(stdin), TCIFLUSH);
read(fileno(stdin), buffer, 10);
}

pthread_mutex_lock(&mybarrier->m_interplayer);
player_status_play |= 1 << sqno;
pthread_mutex_unlock(&mybarrier->m_interplayer);
return 0xff;
}

void sigrtmin_0(int signo)
{
printf("玩家 0 未及时喊牌,系统自动计算\n");
siglongjmp(jmpbuf_hanpai[0], 1);
}

void sigrtmin_1(int signo)
{
printf("玩家 1 未及时喊牌,系统自动计算\n");
siglongjmp(jmpbuf_hanpai[1], 1);
}

void sigrtmin_2(int signo)
{
printf("玩家 3 未及时喊牌,系统自动计算\n");
siglongjmp(jmpbuf_hanpai[2], 1);
}

void sigrtmin_3(int signo)
{
printf("玩家 3 未及时喊牌,系统自动计算\n");
siglongjmp(jmpbuf_hanpai[3], 1);
}

void sigrtmax_0(int signo)
{
printf("玩家 0 太慢了,系统帮助计算\n");
siglongjmp(jmpbuf_calc[0], 1);

}

void sigrtmax_1(int signo)
{
printf("玩家 1 太慢了,系统帮助计算\n");
siglongjmp(jmpbuf_calc[1], 1);

}

void sigrtmax_2(int signo)
{
printf("玩家 2 太慢了,系统帮助计算\n");
siglongjmp(jmpbuf_calc[2], 1);

}

void sigrtmax_3(int signo)
{
printf("玩家 3 太慢了,系统帮助计算\n");
siglongjmp(jmpbuf_calc[3], 1);

}

void player_entry(void *barrier_param)
{
int sqno;
int card;
int err;
int i;
int counter = 0;
int sig_number;
pthread_t tid_temp;
barrier_p mybarrier = (barrier_p) barrier_param;

tid_temp = pthread_self();
sqno = ((mybarrier->player[0] == tid_temp) ? 0
: ((mybarrier->player[1] == tid_temp) ? 1
: ((mybarrier->player[2] == tid_temp) ? 2
: ((mybarrier->player[3] == tid_temp) ? 3 : 0xffff))));
if(sqno == 0xffff) {
printf("未能确认玩家序号\n");
exit(-1);
}
DPRINTF(("玩家 %d 已被正确创建\n", sqno));

while(1) {
/*响应退出*/
RUN_OR_QUIT:
DPRINTF(("player %d jumped\n", sqno));
sigwait (&signal_set, &sig_number);
if (sig_number == SIGUSR1) {
DPRINTF(("player %d got signal\n", sqno));
pthread_mutex_lock(&mybarrier->m_global);
err = pthread_cond_signal(&mybarrier->c_ready_P2RC);
if(err != 0)
ERR_HANDLER(("in player_entry: send signal to R&C"));
pthread_mutex_unlock(&mybarrier->m_global);
}

/*喊牌*/
while(1) {
pthread_mutex_lock(&mybarrier->barrier_hanpai.m_hanpai[1]);
if(quitflag == 1) {
pthread_mutex_unlock(&mybarrier->barrier_hanpai.m_hanpai[1]);
goto RUN_OR_QUIT;
}
pthread_mutex_unlock(&mybarrier->barrier_hanpai.m_hanpai[1]);

if(repeatflag_hanpai == 0)
break;

/*玩家不能在规定时间内喊牌,则强制退出喊牌*/
if(!sigsetjmp(jmpbuf_hanpai[sqno], 1)) {
hanpai(counter, sqno, mybarrier);
printf("玩家 %d 已做决定\n", sqno);
}

/*检测信号量是否被锁住(siglongjmp跳至此处时可能已经获得了互斥锁)*/
if(pthread_mutex_trylock(&mybarrier->m_interplayer) == EBUSY)
pthread_mutex_unlock(&mybarrier->m_interplayer);
else
pthread_mutex_unlock(&mybarrier->m_interplayer);

/*与RC线程同步运行速度*/
pthread_mutex_lock(&mybarrier->barrier_hanpai.m_hanpai[0]);
while(mybarrier->barrier_hanpai.mailbox_hanpai == 1) {
DPRINTF(("玩家 %d 正在等待信号\n", sqno));
err = pthread_cond_wait(&mybarrier->c_RC2P, &mybarrier->barrier_hanpai.m_hanpai[0]);
DPRINTF(("in player_entry, err = %d, player %d\n", err, sqno));
  if(err != 0)
  ERR_HANDLER(("HANPAI: pthread_cond_wait error, in player_entry"));
}
mybarrier->barrier_hanpai.mailbox_hanpai = 1;
pthread_cond_signal(&mybarrier->barrier_hanpai.c_hanpai_P2RC);
DPRINTF(("玩家 %d 发送信号\n", sqno));
pthread_mutex_unlock(&mybarrier->barrier_hanpai.m_hanpai[0]);

counter++;
}
counter = 0;

/*打牌*/
while(1) {
for(i = 0; i < PLAYED_CARDS_NO; i++) {
DPRINTF(("waiting for m_calc[1]\n"));
pthread_mutex_lock(&mybarrier->barrier_calc.m_calc[1]);
pthread_mutex_unlock(&mybarrier->barrier_calc.m_calc[1]);

if(repeatflag_calc == 0)
goto RUN_OR_QUIT;
/*玩家不能在规定时间内出牌,则强制退出出牌过程*/
if(!sigsetjmp(jmpbuf_calc[sqno], 1)) {
DPRINTF(("玩家 %d 开始计算\n", sqno));
card = calculate(sqno, mybarrier);
printf("玩家 %d 计算完毕\n", sqno);
}

/*检测信号量是否被锁住(siglongjmp跳至此处时可能已经获得了互斥锁)*/
if(pthread_mutex_trylock(&mybarrier->m_interplayer) == EBUSY)
pthread_mutex_unlock(&mybarrier->m_interplayer);
else
pthread_mutex_unlock(&mybarrier->m_interplayer);

/*与RC线程同步运行速度*/
pthread_mutex_lock(&mybarrier->barrier_calc.m_calc[0]);
while(mybarrier->barrier_calc.mailbox_calc == 1) {
DPRINTF(("玩家 %d 正在等待信号\n", sqno));
err = pthread_cond_wait(&mybarrier->c_RC2P,
&mybarrier->barrier_calc.m_calc[0]);
DPRINTF(("in player_entry, err = %d, player %d\n", err, sqno));
  if(err != 0)
  ERR_HANDLER(("CALC: pthread_cond_wait error, in player_entry"));
}
mybarrier->barrier_calc.mailbox_calc = 1;
pthread_cond_signal(&mybarrier->barrier_calc.c_calc_P2RC);
DPRINTF(("玩家 %d 发送信号\n", sqno));
pthread_mutex_unlock(&mybarrier->barrier_calc.m_calc[0]);
}
}
}
}

/*检测玩家是否继续游戏*/
int goon_or_not(int *flag, char *buffer)
{
int playagainflag = 1;
int count;

while(1)
{
count = read(fileno(stdin), buffer, BUFFER_RECV);
if(buffer[count - 1] == '\n') {
if(count == 1) {
if(*flag == 0)
break;
else {
DPRINTF(("%d\n", __LINE__));
printf("error! input y(if yes) or n(if no)\n");
continue;
}
} else if(count == 2) {
if(*flag == 0 && buffer[0] == 'y') {
DPRINTF(("here, %d\n", __LINE__));
break;
}
else if(*flag == 0 && buffer[0] == 'n') {
playagainflag = 0;
return playagainflag;
}
else {
DPRINTF(("%d\n", __LINE__));
printf("error! input y(if yes) or n(if no)\n");
continue;
}
} else {
DPRINTF(("%d\n", __LINE__));
*flag = 0;
printf("error! input y(if yes) or n(if no)\n");
continue;
}
} else {
*flag = 1;
continue;
}
}
memset(buffer, '\0', BUFFER_RECV);
*flag = 0;
return playagainflag;
}

int calc_circle_result()
{
printf("本轮结果:玩家 1 获胜\n");
return 1;
}

void calcsuit()
{
printf("计算花色...\n");
}

void help_slow_player(stage_t stg, char status, pthread_t *tid)
{
int i;
int err;
int signo_hanpai[PLAYERCOUNT] = {SIGRTMIN, SIGRTMIN+1, SIGRTMIN+2, SIGRTMIN+3};
int signo_calc[PLAYERCOUNT] = {SIGRTMAX, SIGRTMAX-1, SIGRTMAX-2, SIGRTMAX-3};
DPRINTF(("处理慢速玩家\n"));

switch(stg)
{
case STAGE_HANPAI:
for(i = 0; i < PLAYERCOUNT; i++) {
if(!((status >> i) & 1)) {
printf("嘿,玩家 %d,别磨叽了\n", i);
err = pthread_kill(tid[i], signo_hanpai[i]);
if(err != 0)
ERR_HANDLER(("HANPAI: send signal error, in main"));
}
}
break;
case STAGE_CALC:
for(i = 0; i < PLAYERCOUNT; i++) {
if(!((status >> i) & 1)) {
printf("嘿,玩家 %d,别磨叽了\n", i);
err = pthread_kill(tid[i], signo_calc[i]);
if(err != 0)
ERR_HANDLER(("HANPAI: send signal error, in main"));
}
}
break;
default:
DPRINTF(("error, no such stage\n"));
break;
}
}

void deal()
{
printf("分牌...\n");
}

sighandler_t signal_intr(int signo, sighandler_t func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
if(sigaction(signo, &act, &oact) < 0)
return(oact.sa_handler);
}

void process_control_init(barrier_t *mybarrier)
{
int err = 0;

err = pthread_mutex_init(&mybarrier->barrier_hanpai.m_hanpai[0], NULL);
if(err != 0)
ERR_HANDLER(("initilize m_hanpai[0] error"));
err = pthread_mutex_init(&mybarrier->barrier_hanpai.m_hanpai[1], NULL);
if(err != 0)
ERR_HANDLER(("initilize m_hanpai[1] error"));
err = pthread_cond_init(&mybarrier->barrier_hanpai.c_hanpai_P2RC, NULL);
if(err != 0)
ERR_HANDLER(("initilize c_hanpai_P2RC error"));
err = pthread_mutex_init(&mybarrier->barrier_calc.m_calc[0], NULL);
if(err != 0)
ERR_HANDLER(("initilize m_calc[0] error"));
err = pthread_mutex_init(&mybarrier->barrier_calc.m_calc[1], NULL);
if(err != 0)
ERR_HANDLER(("initilize m_calc[1] error"));
err = pthread_cond_init(&mybarrier->barrier_calc.c_calc_P2RC, NULL);
if(err != 0)
ERR_HANDLER(("initilize c_calc_P2RC error"));
err = pthread_mutex_init(&mybarrier->m_global, NULL);
if(err != 0)
ERR_HANDLER(("initilize m_global error"));
err = pthread_mutex_init(&mybarrier->m_interplayer, NULL);
if(err != 0)
ERR_HANDLER(("initilize m_interplayer error"));
err = pthread_cond_init(&mybarrier->c_RC2P, NULL);
if(err != 0)
ERR_HANDLER(("initilize c_RC2P error"));
err = pthread_cond_init(&mybarrier->c_ready_P2RC, NULL);
if(err != 0)
ERR_HANDLER(("initilize c_ready_P2RC error"));
mybarrier->barrier_hanpai.mailbox_hanpai = 0;
mybarrier->barrier_calc.mailbox_calc = 0;
}

int main(int argc, char **argv)
{
char rcvbuffer[BUFFER_RECV] = {'\0'};
ssize_t count;
int err;
int i, j, circle = 0;
int preparedno_ready = 0;
int preparedno_hanpai = 0;
int preparedno_calc = 0;
int winner;
int temp;
int hanpaipno = 0;
int dealflag = 1;
int badluckcounter = 0, negativecounter = 0;
int totaljuno = 0;
int rcvbufferflag = 0;
int *retval;
sigset_t signal_set_old;
stage_t stage;
barrier_t barrier;

printf("\n********************************************\n");
printf("*All work and no play makes Jack a dull boy*\n");
printf("*Enjoy yourself                            *\n");
printf("********************************************\n");

process_control_init(&barrier);

sigemptyset(&signal_set);
sigaddset(&signal_set, SIGUSR1);
err = pthread_sigmask(SIG_BLOCK, &signal_set, &signal_set_old);
if (err != 0)
ERR_HANDLER(("Set signal mask"));

signal_intr(SIGRTMIN, &sigrtmin_0);
signal_intr(SIGRTMIN+1, &sigrtmin_1);
signal_intr(SIGRTMIN+2, &sigrtmin_2);
signal_intr(SIGRTMIN+3, &sigrtmin_3);
signal_intr(SIGRTMAX, &sigrtmax_0);
signal_intr(SIGRTMAX-1, &sigrtmax_1);
signal_intr(SIGRTMAX-2, &sigrtmax_2);
signal_intr(SIGRTMAX-3, &sigrtmax_3);

pthread_mutex_lock(&barrier.barrier_calc.m_calc[0]);
pthread_mutex_lock(&barrier.barrier_calc.m_calc[1]);
pthread_mutex_lock(&barrier.barrier_hanpai.m_hanpai[0]);
pthread_mutex_lock(&barrier.barrier_hanpai.m_hanpai[1]);

for(i = 0; i < PLAYERCOUNT; i++) {
err = pthread_create(&barrier.player[i], NULL, (void *)player_entry, (void *)&barrier);
if(err != 0)
ERR_HANDLER(("create player thread error"));
}
sleep(1);

while(1) {
/*同步初始进度*/
pthread_mutex_lock(&barrier.m_global);
for(i = 0; i < PLAYERCOUNT; i++) {
pthread_kill(barrier.player[i], SIGUSR1);
err = pthread_cond_wait (&barrier.c_ready_P2RC, &barrier.m_global);
if (err != 0)
ERR_HANDLER( ("Wait for player ready"));
        }
        pthread_mutex_unlock(&barrier.m_global);
if(totaljuno != 0)
pthread_mutex_lock(&barrier.barrier_calc.m_calc[1]);

/*分牌,喊牌*/
stage = STAGE_HANPAI;
while(1) {
if(dealflag == 1)
deal();
printf("请各玩家喊牌\n");

pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[1]);
/*等待玩家喊牌结束*/
for(i = 0; i < PLAYING_WAITING; i++) {
sleep(1);
/*若所有玩家均已做出决定,则不再等待*/
if(player_status_hanpai == 0xf)
break;
}
player_status_hanpai = 0xe; /*此处为演示本程序的效果而设置,可更改*/
if(player_status_hanpai != 0xf)
help_slow_player(stage, player_status_hanpai, barrier.player);

/*与玩家线程同步速度*/
while(preparedno_hanpai < PLAYERCOUNT) {
if(preparedno_hanpai == 0)
pthread_mutex_lock(&barrier.barrier_hanpai.m_hanpai[1]);

err = pthread_cond_wait(&barrier.barrier_hanpai.c_hanpai_P2RC, 
&barrier.barrier_hanpai.m_hanpai[0]);
if(err != 0)
ERR_HANDLER(("HANPAI: pthread_cond_wait error, in main"));
barrier.barrier_hanpai.mailbox_hanpai = 0;
if(preparedno_hanpai < PLAYERCOUNT - 1)
pthread_cond_signal(&barrier.c_RC2P);
preparedno_hanpai++;
DPRINTF(("控制线程接收到 %d 个信号\n", preparedno_hanpai));
}
preparedno_hanpai = 0;

player_hanpai_decision = 0xc0; /*此处模拟各玩家喊牌情况*/
/*若连续3次四个玩家均无资格喊牌,退出。*/
if(player_hanpai_decision == 0x0) {
badluckcounter++;
if(badluckcounter >= 3) {
printf("咦,今天运气怎么这么差?!休息一下再来玩吧:-)\n");
pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[1]);
quitflag = 1;
goto BYE;
}

printf("各玩家均无喊牌资格,重新发牌...\n");
continue;
}

for(i = 0; i < PLAYERCOUNT; i++) {
temp = (player_hanpai_decision >> (i * 2)) & 0x3;
DPRINTF(("temp = %x\n", temp));
if(temp == 0x3) {
hanpaipno++;
printf("玩家 %d 喊牌: %s\n", i, "joker");
}
}

/*若连续3次四个玩家均消极喊牌,退出。*/
if(hanpaipno == 0) {
negativecounter++;
if(negativecounter >= 3) {
printf("大家太消极了,下次再玩吧\n");
quitflag = 1;
pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[1]);
goto BYE;
}
printf("没有玩家喊牌。请有资格的玩家积极喊牌\n");
dealflag = 0;
continue;
} else {
repeatflag_hanpai = 0;
pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[1]);
break;
}
}
negativecounter = 0;
badluckcounter = 0;
dealflag = 1;
hanpaipno = 0;
calcsuit();
printf("主牌花色已确定\n");
printf("\n开战!!!\n");

/*运行每局牌*/
stage = STAGE_CALC;
while(1) {
printf("\n\n第 %d 轮...\n", circle++);

/*同步每轮的 4 次计算*/
for (j = 0; j < PLAYED_CARDS_NO; j++) {
pthread_mutex_unlock(&barrier.barrier_calc.m_calc[1]);

/*给玩家 15s 的出牌时间*/
for(i = 0; i < 5; i++) { /*这里为缩短演示时间,修改为5s*/
sleep(1);
/*若出牌玩家已经出牌,则不再等待*/
if(player_status_play == 0xf)
break;
}
player_status_play = 0x5;
if(player_status_play != 0xf)
help_slow_player(stage, player_status_play, barrier.player);

/*与玩家线程同步速度*/
while(preparedno_calc < PLAYERCOUNT) {
if(preparedno_calc == 0)
pthread_mutex_lock(&barrier.barrier_calc.m_calc[1]);

err = pthread_cond_wait(&barrier.barrier_calc.c_calc_P2RC, 
&barrier.barrier_calc.m_calc[0]);
if(err != 0)
ERR_HANDLER(("CALC: pthread_cond_wait error, in main"));
barrier.barrier_calc.mailbox_calc = 0;
if(preparedno_calc < PLAYERCOUNT - 1)
pthread_cond_signal(&barrier.c_RC2P);
preparedno_calc++;
DPRINTF(("控制线程接收到 %d 个信号\n", preparedno_calc));
}
preparedno_calc = 0;

printf("所有玩家计算完毕, 玩家已出牌\n");
}

/*计算本轮赢家*/
winner = calc_circle_result();
if(circle == 3) {
repeatflag_calc = 0;
pthread_mutex_unlock(&barrier.barrier_calc.m_calc[1]);
break;
}
}
circle = 0;

pthread_mutex_lock(&barrier.barrier_hanpai.m_hanpai[1]);

printf("Go on playing?(y/n). Press Enter key directly if continue\n");
tcflush(fileno(stdin), TCIFLUSH);
if(goon_or_not(&rcvbufferflag, rcvbuffer) == 0)
break;

repeatflag_hanpai = 1;
repeatflag_calc = 1;
totaljuno++;
}

BYE:
printf("R&C say bye to players\n");
for(i = 0; i < PLAYERCOUNT; i++) {
        pthread_cancel(barrier.player[i]);
        pthread_join(barrier.player[i], (void **)&retval);
        if(retval == PTHREAD_CANCELED)
            DPRINTF(("thread %d exit\n", i));
    }

pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[1]);
pthread_mutex_unlock(&barrier.barrier_calc.m_calc[0]);
pthread_mutex_unlock(&barrier.barrier_calc.m_calc[1]);
pthread_mutex_unlock(&barrier.barrier_hanpai.m_hanpai[0]);
exit(0);
}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多