问题
I am new to programming and wrote a small Pong game for an assignment using multiple threads, one thread for each ball. This programs works really well on Ubuntu but when I run in on Red Hat all sorts of crazy characters appear on the screen randomly. It seem to happening quicker the more balls I use.
Here is the code. It is run by using "pong a b c d" for example which will produce balls on the screen using the character symbols as the ball. I am pretty sure the issue is inside the animate function as that is where all the refreshing and moving is done. But don't know what the issue is.
#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);
}
I know it is a lot of code to read through. I am happy to cut it down.
here is what it looks like on Red Hat
This is what it looks like on Ubuntu.
回答1:
Your code implicitly operates on the "current screen" in ncurses, a shared object, which is not thread safe. There is a mutex, but you are not consistently holding it across all calls to ncurses. This might not be the issue you're seeing, but it's a gaping problem.
来源:https://stackoverflow.com/questions/19749038/c-junk-appearing-on-screen-using-curses