多进程(提高了复杂性)
多线程(需要同步机制)
NONBLOCKING I/O(持续polling消耗了CPU时间)
异步I/O(难以移植,且进程只有拥有一个某类型的信号)
IO multiplexing
其中,IO multiplexing是最好的方法。
为了进行IO复用的实验,我使用了一个STM32F103RBT6开发板作为串口设备。
它的功能是,将自身的串口1设置为115200 8N1的波特率,并返回任何接收到的字符串。
字符串以'\r'作为结束:
比如在minicom下通过键盘发送“123456abc\r”,那么就会接收到:
R: 123456abc
如果连续键入'\r'(minicom默认以此字符作为Enter键的输入),则有:
R:
R:
R:
在主函数里,将串口进行初始化操作:
fd_dev = ::open(DEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
if (fd_dev < 0) {
cerr << "Error: Cannot open " << DEVICE << endl;
return -1;
}
termios attr;
memset(&attr, 0, sizeof(attr));
attr.c_cflag = B115200 | HUPCL | CS8 | CREAD | CLOCAL;
attr.c_iflag = IGNPAR;
attr.c_cc[VMIN] = 1;
if (tcsetattr(fd_dev, TCSANOW, &attr) != 0) {
cerr << "Error: Cannot set termios!" << endl;
return -1;
}
然后重新起一个线程,让它每隔一秒发送一串数据:
void *ntid2_print(void *arg)
{
string str;
int count = 0, flag;
while (1) {
str = "<2> Write " + to_string(count++) + "th times." + "\r";
cout << "=> " << str.c_str() << endl;
flag = ::write(fd_dev, str.c_str(), str.size());
if (flag < 0)
cerr << "Error: Cannot write!" << endl;
sleep(1);
}
return ((void *)0);
}
执行的结果是:
# ./UnixProg_01
=> <2> Write 0th times.
=> <2> Write 1th times.
=> <2> Write 2th times.
=> <2> Write 3th times.
这样,串口每隔1s就会收到1个字符串,而标准输入会接收键盘数据。
现在,我需要的功能是,主函数既能够读取串口的数据,也能够读取标准IO的,并将它们都打印到标准输出上。
这里需要使用IO复用的select函数:
fd_set rset;
char byte;
while (1) {
FD_ZERO(&rset);
FD_SET(fd_dev, &rset);
FD_SET(STDIN_FILENO, &rset);
select(fd_dev + 1, &rset, NULL, NULL, NULL);
if (FD_ISSET(fd_dev, &rset)) {
flag = ::read(fd_dev, &byte, 1);
if (flag < 0) {
cerr << "Error: Cannot read fd_dev!" << endl;
return -1;
}
cout << byte << flush;
}
if (FD_ISSET(STDIN_FILENO, &rset)) {
flag = ::read(STDIN_FILENO, &byte, 1);
if (flag < 0) {
cerr << "Error: Cannot read fd_dev!" << endl;
return -1;
}
cout << byte << flush;
}
}
这样,标准输出既会打印串口的数据,又会打印标准输入的内容。
另外,还需要注意的一点是,STDIN_FILENO的FD_SET在循环里面,这是因为:
http://stackoverflow.com/questions/7637765/why-fd-set-fd-zero-for-select-inside-of-loop
curton 2019-4-30 19:06
curton 2019-4-26 12:52
用户1678053 2016-5-30 09:08