The sample of O_ASYNC and aio_read

来源:互联网 发布:什么网络大型游戏 编辑:程序博客网 时间:2024/06/05 20:51
O_ASYNC 和 aio_read 示例代码, 主要用来示范Linux中的信号量.

代码为一个游戏,用*去捕捉小球,
Q --退出
S,s,F,f --加快或减缓小球x或y方向移动速度
z,x--改变小球x或y轴移动方向
i,j,k,l 移动*号.

bounce.h:
/* bounce.h
 * somet settings for the game
 
*/

#ifndef bounce_h
    
#define bounce_h

    #include 
<aio.h>
    #include 
<curses.h>
    #include 
<fcntl.h>
    #include 
<string.h>
    #include 
<unistd.h>

    
#define BLANK ' '
    
#define DFL_SYMBOL 'o'
    
#define PL_SYMBOL '*'
    
#define TOP_ROW 5
    
#define BOT_ROW 20
    
#define LEFT_EDGE 10
    
#define RIGHT_EDGE 70
    
#define X_INIT 10                // starting col
    
#define Y_INIT 10                // starting row
    
#define TICKS_PER_SEC 50            // affects speed
    
#define X_TTM 8
    
#define Y_TTM 8

    
int done = 0;
    
int score = 0;

    
// the ping pong ball
    struct ppball{
        
int y_pos,x_pos,
            y_ttm,x_ttm,
            y_ttg,x_ttg,
            y_dir,x_dir;
        
char symbol;
    }
;

    
// the player
    struct player {
        
int y_pos,x_pos;
        
char symbol;
    }
;

    
struct aiocb kbcbuf;
    
struct ppball the_ball;
    
struct player the_player;

    
int set_ticker(int);
    
void draw_wall();
    
void draw_score();
    
void draw_player();
    
void move_player(char);
#endif
bounce2d.c:
/* bounce2d 1.0
 * bounce a character (defaults is 'o') around the screen
 * defined by some paraments
 *
 * user input: 
 *     s slow down x component, S: slow y component
 *     f speed up x component, F: speed y component
 *     Q quit
 * 
 * purpose animation with use control, using aio_read() or O_ASYNC
 * timer tick sends SIGALRM, handler does animation
 * keybords sends SIGIO
 * main only class pause()
 * build: cc bounce2d.c set_ticker.c -lcurses -l rt-o bounce2d
 
*/

#include 
"bounce.h"


// the main loop

void set_up();
void wrap_up();

int main() {
    set_up();

    
while(!done)                     // the main loop
        pause();
    
    wrap_up();

    
return 0;
}


/*
 * init structure and other stuff
 
*/

void set_up() {
    
void ball_move(int);
    
void enable_kdb_signals();
    
void setup_aio_buffer();
    
void on_input(int);

    
// setup the ball's state
    the_ball.y_pos = Y_INIT;        
    the_ball.x_pos 
= X_INIT;
    the_ball.y_ttg 
= the_ball.y_ttm = Y_TTM;
    the_ball.x_ttg 
= the_ball.x_ttm = X_TTM;
    the_ball.y_dir 
= 1;
    the_ball.x_dir 
= 1;
    the_ball.symbol 
= DFL_SYMBOL;

    done 
= 0;

    initscr();                    
// setup the screen
    noecho();
    crmode();
    clear();
    
    
// setup the player's state and draw the player
    the_player.x_pos = LEFT_EDGE;
    the_player.y_pos 
= TOP_ROW;
    the_player.symbol 
= PL_SYMBOL;
    draw_player();

    
// draw the wall
    draw_wall();

    
// setup and draw the score
    score = 0;
    draw_score();

    signal(SIGINT,SIG_IGN);
    mvaddch(the_ball.y_pos,the_ball.x_pos,the_ball.symbol);
    refresh();

    signal(SIGIO,on_input);                
// install a handler
    
    
// use O_ASYNC
//    enable_kdb_signals();                // turn on kbd signals
    
    
// use aio_read
    setup_aio_buffer();                // initialize aio ctrl buff
    aio_read(&kbcbuf);                // place a read quest

    signal(SIGALRM,ball_move);            
// install alarm handler
    set_ticker(1000/TICKS_PER_SEC);            // send millisecs per tick
}


void wrap_up() {
    set_ticker(
0);
    endwin();                    
// put back normal
}


void ball_move(int signum) {
    
int y_cur,x_cur,moved;
    
    
int bounce_or_lose(struct ppball *);

    signal(SIGALRM,ball_move);            
// don't get caught now
    y_cur = the_ball.y_pos;                // old spot
    x_cur = the_ball.x_pos;
    moved 
= 0;

    
if(the_ball.y_ttm > 0 && --the_ball.y_ttg == 0{
        the_ball.y_pos 
+= the_ball.y_dir;    // move
        the_ball.y_ttg = the_ball.y_ttm;    // reset
        moved = 1;
    }


    
if(the_ball.x_ttm > 0 && --the_ball.x_ttg == 0{
        the_ball.x_pos 
+= the_ball.x_dir;    // move
        the_ball.x_ttg = the_ball.x_ttm;    // reset
        moved = 1;
    }


    
if(moved) {
        mvaddch(y_cur,x_cur,BLANK);
        
// mvaddch(y_cur,x_cur,BLANK);
        mvaddch(the_ball.y_pos,the_ball.x_pos,the_ball.symbol);
        
if(bounce_or_lose(&the_ball)) {
            
++score;
            draw_score();
            draw_wall();
        }

        move(LINES 
- 1,COLS - 1);
        refresh();
    }

    signal(SIGALRM,ball_move);            
//  for unreliable systems
}


int bounce_or_lose(struct ppball *bp) {
    
int return_val = 0;

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


    
if(bp -> x_pos <= LEFT_EDGE) {
        bp 
-> x_dir = 1;
    }
 else if(bp -> x_pos >= RIGHT_EDGE) {
        bp 
-> x_dir = -1;
    }


    
if(bp -> x_pos == the_player.x_pos 
        
&& bp -> y_pos == the_player.y_pos)
        return_val 
= 1;

    
return return_val;
}


/* 
 * intstall a handler, tell kernel who to notify on input, enable signals
 
*/

void enable_kdb_signals() {
    
int fd_flags;

    fcntl(
0,F_SETOWN,getpid());
    fd_flags 
= fcntl(0,F_GETFL);
    fcntl(
0,F_SETFL,(fd_flags | O_ASYNC));
}


/*
 * handler called to when aio_read() has stuff to read
 * First check for any errors codes, and if ok, then get the return code
 
*/

void on_input(int signum) {
    
int c;

    
while((c = getchar()) != 'Q'{
        
if(c == 'f'--the_ball.x_ttm;
        
else if(c == 's'++the_ball.x_ttm;
        
else if(c == 'F'--the_ball.y_ttm;
        
else if(c == 'S'++the_ball.y_ttm;
        
else if(c == 'z'
            the_ball.x_dir 
= -the_ball.x_dir;
        
else if(c == 'x')
            the_ball.y_dir 
= -the_ball.y_dir;
        
else if(c == 'i' || c == 'j' || c == 'k' || c == 'l')
            move_player(c);
    }


    done 
= 1;
}


/*
 * set memebers of struct
 * First specify args like those for read(fd,buf,num) and offset
 * Then specify what to do(send signal) and what signal(SIGIO)
 
*/

void setup_aio_buffer() {
    
static char input[1];                // 1 char of input

    
// describe what to read
    kbcbuf.aio_fildes = 0;                // standard input
    kbcbuf.aio_buf = input;                // buffer
    kbcbuf.aio_nbytes = 1;                // number to read
    kbcbuf.aio_offset = 0;                // offset in file

    
// describe what to do when read is ready
    kbcbuf.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
    kbcbuf.aio_sigevent.sigev_signo 
= SIGIO;    // send SIGIO
}


/*
 * draw the wall when setup.
 
*/

void draw_wall() {
    
int i,j;
    
    
// draw four corner
    mvaddch(TOP_ROW - 1,LEFT_EDGE - 1,'+');
    mvaddch(BOT_ROW 
+ 1,LEFT_EDGE - 1,'+');
    mvaddch(TOP_ROW 
- 1,RIGHT_EDGE + 1,'+');
    mvaddch(BOT_ROW 
+ 1,RIGHT_EDGE + 1,'+');

    
// draw top row
    for(i = LEFT_EDGE,j = TOP_ROW - 1; i <= RIGHT_EDGE; ++i) {
        mvaddch(j,i,
'-');
    }


    
// draw left column
    for(i = LEFT_EDGE - 1,j = TOP_ROW; j <= BOT_ROW; ++j) {
        mvaddch(j,i,
'|');
    }


    
// draw botton row
    for(i = LEFT_EDGE,j = BOT_ROW + 1; i <= RIGHT_EDGE; ++i) {
        mvaddch(j,i,
'-');
    }


    
// draw right column
    for(i = RIGHT_EDGE + 1,j = TOP_ROW; j <= BOT_ROW; ++j) {
        mvaddch(j,i,
'|');
    }

}


/*
 * draw score on the left top corner
 
*/

void draw_score() {
    
char score_string[100];
    sprintf(score_string,
"score:%d",score);
    move(
1,1);
    addstr(score_string);
}


/*
 * draw the player
 
*/

void draw_player() {
    mvaddch(the_player.y_pos,the_player.x_pos,the_player.symbol);    
}


/*
 * move the player
 
*/

void move_player(char input) {
    mvaddch(the_player.y_pos,the_player.x_pos,BLANK);    
    
switch(input) {
        
case 'i':
            
if(the_player.y_pos > TOP_ROW)
                
--the_player.y_pos;
            
break;
        
case 'k':
            
if(the_player.y_pos < BOT_ROW)
                
++the_player.y_pos;
            
break;
        
case 'j':
            
if(the_player.x_pos > LEFT_EDGE)
                
--the_player.x_pos;
            
break;
        
case 'l':
            
if(the_player.x_pos < RIGHT_EDGE)
                
++the_player.x_pos;
            
break;
    }

    draw_player();
}

set_ticker.c:
#include    <stdio.h>
#include        
<sys/time.h>
#include        
<signal.h>

/*
 *      set_ticker.c
 *          set_ticker( number_of_milliseconds )
 *                   arranges for the interval timer to issue
 *                   SIGALRM's at regular intervals
 *          returns -1 on error, 0 for ok
 *
 *      arg in milliseconds, converted into micro seoncds
 
*/



int set_ticker( int n_msecs )
{
        
struct itimerval new_timeset;
        
long    n_sec, n_usecs;

        n_sec 
= n_msecs / 1000 ;
        n_usecs 
= ( n_msecs % 1000 ) * 1000L ;

        new_timeset.it_interval.tv_sec  
= n_sec;        /* set reload  */
        new_timeset.it_interval.tv_usec 
= n_usecs;      /* new ticker value */
        new_timeset.it_value.tv_sec     
= n_sec  ;      /* store this   */
        new_timeset.it_value.tv_usec    
= n_usecs ;     /* and this     */

    
return setitimer(ITIMER_REAL, &new_timeset, NULL);
}



makefile:
bounce2d: bounce2d.c bounce.h set_ticker.c
    gcc 
$^ -l curses -l rt -o $@ -Wall
原创粉丝点击