C, junk appearing on screen using curses

99封情书 提交于 2020-01-24 21:30:42

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!