最近遇到一个需求:linux下的程序在忽略其他退出信号的情况下,按q键退出。
由于主线程需要监听键盘输入,正常情况读取字符串会阻塞,导致主线程无法正常退出,因此考虑用非阻塞的形式实现。
在linux下每打开一个终端,系统自动的就打开了三个文件,它们的文件描述符分别为0,1,2,功能分别是“标准输入”、“标准输出”和“标准错误输出”,同时对应了三个文件流指针,分别是stdin,stdout和stderr。
使用ioctl清除非阻塞标志
函数原型:
int ioctl(int d, int request, …);
参数:
d:文件描述符
request:功能码。根据填写的功能码选择第三个参数。
返回:
成功返回0,失败返回-1。
ioctl函数传入的第二个参数为FIONBIO表示“设置/清除非阻塞标志”,那么第三个参数要传入一个int类型的指针,指针指向的值为1表示设置非阻塞标志,那么对应的文件描述符为非阻塞,指针指向的值为0表示清除非阻塞标志,那么对应的文件描述符为阻塞。
因此调用如下代码即可实现非阻塞:
int attr = 1;
ioctl(STDIN_FILENO, FIONBIO, &attr); /* 清除非阻塞标志 */
完整代码如下:
// 处理中途退出程序
char buf[128] = { 0 };
int len = 0;
int total = 0;
int attr = 1;
ioctl(STDIN_FILENO, FIONBIO, &attr); /* 清除非阻塞标志 */
printf("input 'q' to quit \n");
while (!read_quit || !send_quit)
{
len = read(STDIN_FILENO, &buf[total], sizeof(buf) - total);
//printf("len = %d\n", len);
if (len > 0) {
total += len;
if (buf[total - 1] == '\n') {
//printf("total = %d\n", total);
//printf("buf = %s\n", buf);
if (buf[0] == 'q')
{
//退出处理
break;
}
total = 0;
memset(buf, 0, sizeof(buf));
}
}
msleep(2000);
}
//退出时记得恢复阻塞输入
attr = 0;
ioctl(STDIN_FILENO,FIONBIO,&attr);//attr为0