C, мусор, появляющийся на экране с использованием ругательств

Я новичок в программировании и написал небольшую игру Pong для задания с использованием нескольких потоков, по одному потоку для каждого мяча. Эти программы очень хорошо работают в Ubuntu, но когда я запускаю Red Hat, на экране случайным образом появляются всевозможные сумасшедшие символы. Кажется, это происходит тем быстрее, чем больше мячей я использую.

Вот код. Например, он запускается с использованием «pong a b c d», который будет создавать шары на экране, используя символы символов в качестве мяча. Я почти уверен, что проблема заключается в функции анимации, поскольку именно здесь выполняется все обновление и перемещение. Но не знаю, в чем дело.

#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. введите здесь описание изображения


person user2661167    schedule 03.11.2013    source источник
comment
где определены nstrings? Понг.ч?   -  person Charlie Burns    schedule 03.11.2013
comment
nstrings — это просто ac-1 из main()   -  person user2661167    schedule 03.11.2013


Ответы (1)


Ваш код неявно работает с «текущим экраном» в ncurses, общим объектом, который не является потокобезопасным. Есть мьютекс, но вы не всегда поддерживаете его при всех вызовах ncurses. Это может быть не та проблема, которую вы видите, но это зияющая проблема.

person Kaz    schedule 03.11.2013
comment
Так должен ли я вызывать блокировку потока каждый раз, когда я что-то меняю на экране? - person user2661167; 03.11.2013
comment
Большое спасибо, я убедился, что любые вызовы проклятий были в блокировках потока, и это устранило проблемы, которые, как я считаю. - person user2661167; 03.11.2013