linux 函数异步,linux中实现对输入的异步

1:传统的输入信号

传统的输入都是通过阻塞来实现,例如getchar一直等待用户输入。又或者是再curses库中的getch都是通过阻塞的方式来等待用户输入。那么想象一个场景要设计一个游戏,这个游戏可以让玩家动态输入一些值来动态调整游戏参数。不可能通过getchar这样的阻塞函数来获取用户输入把。那么这个该如何实现呢,再想象一下另外一种场景操作系统的CPU不可能是一直等待网卡的输入把。所以对于一些特别的场景阻塞输入是无法满足要求的。下面的这个例子就是一个阻塞输入的例子。#include

#include

#include

void init_setup (  );

void init_end (  );

void on_input (  );

void do_main (  );

int main ( int argc, char *argv[] )

{

init_setup();

on_input();

do_main();

init_end();

return EXIT_SUCCESS;

}

/* ----------  end of function main  ---------- */

void init_setup (  )

{

initscr();

crmode();

noecho();

clear();

}               /* -----  end of function init_setup  ----- */

void init_end (  )

{

endwin();

}               /* -----  end of function init_end  ----- */

void on_input (  )

{

char c;

while((c = getch()) != 'q'){

if(c == 'w')

mvaddch(20,20,'!');

else if(c == 'e')

mvaddch(20,20,'0');

else if(c == 'r')

mvaddch(20,20,'t');

}

}               /* -----  end of function on_input  ----- */

void do_main (  )

{

while(1){

move(50,50);

addstr("do other thing");

}

}               /* -----  end of function do_main  ----- */

从这个例子可以发现do_main没有执行,因为on_input一直等待用户输入阻塞了下面的程序运行。所以在有些场景像getchar或者getch这类的阻塞函数无法满足一些需求,那么就需要使用异步IO。异步IO的实现有两种方法:

1.设置输入O_ASYNC位

2.使用aio_read()

2:异步输入一

步骤如下:

1.设置0描述符,当输入就绪的时候发送信号

2.设置0描述符O_ASYNC标志位

2.设置信号处理函数。

下面是一个例子:

#include

#include

#include

#include

#include

void init_setup (  );

void init_end (  );

void on_input (  );

void do_main (  );

void enable_kdb_signals();

int main ( int argc, char *argv[] )

{

init_setup();

enable_kdb_signals();

signal(SIGIO,on_input);

do_main();

init_end();

return EXIT_SUCCESS;

}

/* ----------  end of function main  ---------- */

void init_setup (  )

{

initscr();

crmode();

noecho();

clear();

}               /* -----  end of function init_setup  ----- */

void init_end (  )

{

endwin();

}               /* -----  end of function init_end  ----- */

void on_input (  )

{

char c;

c = getch();

if(c == 'w')

mvaddch(20,20,'!');

else if(c == 'e')

mvaddch(20,20,'0');

else if(c == 'r')

mvaddch(20,20,'t');

}               /* -----  end of function on_input  ----- */

void do_main (  )

{

while(1){

sleep(1);

move(50,50);

addstr("do other thing");

refresh();

}

}               /* -----  end of function do_main  ----- */

//设置输入时发送信号,设置输入为O_ASYNC

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));

}

上面这个例子可以看到do other thing以及输出,do_main正在运行,但是此时你输入字符程序可以通过信号处理函数on_input来接受输入进行响应。达到了异步的效果。

3:异步输入二

异步输入的第二种方法是通过aio_read来实现的,使用aio_read更加灵活,但是设置起来也比较复杂。

设置步骤如下:

1.设置信号处理函数,接受用户输入

2.设置aiocb结构体中的变量指明等待什么类型的输入,当输入的时候产生什么信号。

3.将aiocb结构体传递给aio_read来递交读入请求。

aiocb结构体定义如下:struct aiocb {

/* The order of these fields is implementation-dependent */

int             aio_fildes;     /* File descriptor */

off_t           aio_offset;     /* File offset */

volatile void  *aio_buf;        /* Location of buffer */

size_t          aio_nbytes;     /* Length of transfer */

int             aio_reqprio;    /* Request priority */

struct sigevent aio_sigevent;   /* Notification method */

int             aio_lio_opcode; /* Operation to be performed;

lio_listio() only */

/* Various implementation-internal fields not shown */

};

struct sigevent {

int          sigev_notify; /* Notification method */

int          sigev_signo;  /* Notification signal */

union sigval sigev_value;  /* Data passed with

notification */

void       (*sigev_notify_function) (union sigval);

/* Function used for thread

notification (SIGEV_THREAD) */

void        *sigev_notify_attributes;

/* Attributes for notification thread

(SIGEV_THREAD) */

pid_t        sigev_notify_thread_id;

/* ID of thread to signal (SIGEV_THREAD_ID) */

};

下面是一个简单的例子:#include

#include

#include

#include

#include

#include

void init_setup (  );

void init_end (  );

void on_input (  );

void do_main (  );

void setup_aio_buffer();

struct aiocb kbcbuf;

int main ( int argc, char *argv[] )

{

init_setup();

signal(SIGIO,on_input);

setup_aio_buffer();

aio_read(&kbcbuf);

do_main();

init_end();

return EXIT_SUCCESS;

}

/* ----------  end of function main  ---------- */

void init_setup (  )

{

initscr();

crmode();

noecho();

clear();

}               /* -----  end of function init_setup  ----- */

void init_end (  )

{

endwin();

}               /* -----  end of function init_end  ----- */

void on_input (  )

{

char c;

char *cp = (char *)kbcbuf.aio_buf;

if(aio_error(&kbcbuf) != 0)

perror("reading faild");

else

if(aio_return(&kbcbuf) ==1){

c = *cp;

if(c == 'w')

mvaddch(20,20,'!');

else if(c == 'e')

mvaddch(20,20,'0');

else if(c == 'r')

mvaddch(20,20,'t');

}

aio_read(&kbcbuf);

}               /* -----  end of function on_input  ----- */

void do_main (  )

{

while(1){

sleep(1);

move(50,50);

addstr("do other thing");

refresh();

}

}               /* -----  end of function do_main  ----- */

void setup_aio_buffer()

{

static char input[1];

kbcbuf.aio_fildes = 0;

#设置接受输入的buf

kbcbuf.aio_buf = input;

#设置接受输入的字节大小

kbcbuf.aio_nbytes = 1;

kbcbuf.aio_offset = 0;

#设置处理输入的方法

#SIGE_SIGNAL 代表通过发送信号来处理

kbcbuf.aio_sigevent.sigev_notify =SIGEV_SIGNAL;

#设置要发送的信号

kbcbuf.aio_sigevent.sigev_signo = SIGIO;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值