1

我是编程新手,使用多个线程编写了一个小型乒乓球游戏,每个球一个线程。这个程序在 Ubuntu 上运行得非常好,但是当我在 Red Hat 上运行时,各种疯狂的字符随机出现在屏幕上。我使用的球越多,它似乎发生得越快。

这是代码。例如,它通过使用“pong abc d”运行,它将使用字符符号作为球在屏幕上产生球。我很确定问题出在 animate 函数内部,因为这是所有刷新和移动完成的地方。但是不知道是什么问题。

#include    <stdio.h>
#include    <curses.h>
#include    <pthread.h>
#include    <stdlib.h>
#include    <unistd.h>
#include    <fcntl.h>
#include    "Pong.h"

#define MAXBALL 10              /* limit of balls   */

int game_over   = 0;            /* game over flag   */
int num_msg;                    /* number of balls  */
int select_ball;                /* select ball      */

struct ppball   balls[MAXBALL]; /* array of balls   */
struct paddle   the_paddle ;    /* paddle           */
struct window   the_window ;    /* window           */
pthread_t       thrds[MAXBALL]; /* the threads      */

void    set_ticker();           /* the animation    */
void    paddle_move(int move);  /* the animation    */
void    wrap_up();              /* the animation    */
void    *animate();             /* the animation    */

pthread_mutex_t mx = PTHREAD_MUTEX_INITIALIZER;

int main(int ac, char *av[]){

    int i; /* for loops */
    select_ball = 0;

    if ( ac == 1 ){
        printf("usage: Pong char ..\n"); 
        exit(1);
    }

    num_msg = setup(ac-1,av+1,balls);

    /* draw the window to the screen */
    the_window.win = newwin(20, 60, 1, 1);
    wborder(the_window.win, 0, ' ', 0, 0, 0, 0, 0, 0);
    refresh();
    wrefresh(the_window.win);


    /* create all the threads */
    for( i=0 ; i<num_msg; i++ ){
        if ( pthread_create(&thrds[i], NULL, animate, &balls[i]) ){
            fprintf(stderr,"error creating thread");
            endwin();
            exit(0);
        }
    }


    while( game_over != 1 ){    /* the main loop */
        int c = getch();        /* grab char */

        if( c == 'Q' ) {
            game_over = 1;
        }
    else if( c == 'S' ){
        for(i=0 ; i<num_msg; i++){
            if( balls[i].stimer > INCREMENT ){
                balls[i].stimer = balls[i].stimer + INCREMENT;
            }
        }
    }
    else if( c == 'F' ){
        for(i=0 ; i<num_msg; i++){
            if( balls[i].stimer > INCREMENT ){
                balls[i].stimer = balls[i].stimer - INCREMENT;
            }
        }
    }
    else if( c == 'a' ){
        if( the_paddle.mid_x_pos >= TOP_ROW + 2){
            paddle_move(0);
        }
    }
    else if( c == 'z' ){
        if( the_paddle.mid_x_pos <= BOT_ROW-2){
            paddle_move(1);
        }   
    }
}

for ( i=0; i<num_msg; i++ ){
    pthread_cancel(thrds[i]);
}

wrap_up();
return 0;
}


void wrap_up(){
curs_set(1);
clear();
endwin();
}

int setup(int nstrings, char *strings[], struct ppball ball[]){
int num_msg = ( nstrings > MAXBALL ? MAXBALL : nstrings );
int i;

/* assign positions and direction to each ball */
srand(getpid());
for(i=0 ; i<num_msg; i++){
    ball[i].stimer = START_TIMER;
    ball[i].y_pos = rand() % 10 + 2;
    ball[i].x_pos = rand() % 10 + 5;
    ball[i].y_dir = ((rand()%2)?1:-1);  ;
    ball[i].x_dir = ((rand()%2)?1:-1);  ;
    ball[i].symbol = *strings[i];
}

/* set up paddle */
the_paddle.y_pos = PADDLE_Y_INIT;
the_paddle.top_x_pos = PADDLE_X_INIT-1;
the_paddle.mid_x_pos = PADDLE_X_INIT;
the_paddle.bot_x_pos = PADDLE_X_INIT+1;
the_paddle.symbol = PADDLE_SYMBOL ;

/* set up curses */
initscr();
crmode();
noecho();
clear();
curs_set(0);

return num_msg;

}

void *animate(void *arg)
{
struct ppball *info = arg;      /* point to info block  */
int i;
while( game_over != 1 ){

    usleep(info->stimer);

    if ( info->y_pos == TOP_ROW ){
        info->y_dir = 1 ; 
    } else if ( info->y_pos == BOT_ROW ){
        info->y_dir = -1 ;
    }

    /* check if ball hits paddle */
    if ( (info->y_pos == the_paddle.top_x_pos || info->y_pos == the_paddle.mid_x_pos || info->y_pos == the_paddle.bot_x_pos ) && info->x_pos == the_paddle.y_pos ){
        info->x_dir = -1;
    }

    if ( info->x_pos == LEFT_EDGE ){
        info->x_dir = 1 ;
    } else if ( info->x_pos == RIGHT_EDGE ){
        /* if ball hits right edge program ends */
        game_over = 1;
    }

    /* erase ball */
    mvaddch( info->y_pos, info->x_pos, BLANK );

    info->y_pos += info->y_dir ;    /* move */
    info->x_pos += info->x_dir ;    /* move */

    pthread_mutex_lock(&mx);        
    mvaddch( info->y_pos, info->x_pos, info->symbol );
    mvaddch( the_paddle.top_x_pos, the_paddle.y_pos, the_paddle.symbol );
    mvaddch( the_paddle.mid_x_pos, the_paddle.y_pos, the_paddle.symbol );
    mvaddch( the_paddle.bot_x_pos, the_paddle.y_pos, the_paddle.symbol );
    pthread_mutex_unlock(&mx);  

    mvprintw(LINES-3,3,"'a' and 'z' to move paddle");
    mvprintw(LINES-2,3,"'S' and 'F' dec/inc all ball speed.");
    mvprintw(LINES-1,3,"'s' and 'f' dec/inc %c speed, 'w' or 'r' to change ball",   balls[select_ball].symbol );

    refresh();  
}
    mvprintw(10,10,"Game Over");
}

void paddle_move(int move)
{
pthread_mutex_lock(&mx);
mvaddch( the_paddle.top_x_pos, the_paddle.y_pos, BLANK );
mvaddch( the_paddle.mid_x_pos, the_paddle.y_pos, BLANK );
mvaddch( the_paddle.bot_x_pos, the_paddle.y_pos, BLANK );

if( move == 0 && the_paddle.mid_x_pos >= TOP_ROW + 1){
    the_paddle.top_x_pos--;
    the_paddle.mid_x_pos--;
    the_paddle.bot_x_pos--;
    refresh();  
}
else if( move == 1 && the_paddle.mid_x_pos <= BOT_ROW-3){
    the_paddle.top_x_pos++;
    the_paddle.mid_x_pos++;
    the_paddle.bot_x_pos++;
}
mvaddch( the_paddle.top_x_pos, the_paddle.y_pos, the_paddle.symbol );
mvaddch( the_paddle.mid_x_pos, the_paddle.y_pos, the_paddle.symbol );
mvaddch( the_paddle.bot_x_pos, the_paddle.y_pos, the_paddle.symbol );
refresh();  
pthread_mutex_unlock(&mx);
}

我知道要通读很多代码。我很高兴把它剪掉。

这是 Red Hat 上的样子 在此处输入图像描述

这就是它在 Ubuntu 上的样子。 在此处输入图像描述

4

1 回答 1

2

您的代码在 ncurses 中的“当前屏幕”上隐式操作,这是一个共享对象,它不是线程安全的。有一个互斥锁,但您并没有在所有对 ncurses 的调用中始终持有它。这可能不是您看到的问题,但这是一个巨大的问题。

于 2013-11-03T02:01:03.663 回答