select用来等待信号发生,如果有信号发生,就会给用户机会处理信号。
1 等待键盘信号
下面的程序等待用户从键盘输入,如果没有输入,就一直等待:
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
fd_set read_fd_set;
FD_ZERO(&read_fd_set);
FD_SET(0,&read_fd_set);
int ret = select(1,&read_fd_set,NULL,NULL, nullptr);
if(ret == 0) //超时
{
printf("select time out!\n");
}
else if(ret == -1) //失败
{
printf("fail to select!\n");
}
else //成功
{
printf("data is available! ret=%d\n", ret);
}
return 0;
}
运行:
上面的程序一直在等待,如果你敲回车,程序就会知道有输入:
2 从键盘获取输入
#include <sys/select.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <cassert>
#include <iostream>
using namespace std;
int main()
{
fd_set read_fd_set;
FD_ZERO(&read_fd_set);
FD_SET(0,&read_fd_set);
while (true)
{
int ret = select(1, &read_fd_set, NULL, NULL, nullptr);
if (ret == 0) //超时
{
printf("select time out!\n");
}
else if (ret == -1) //失败
{
printf("fail to select!\n");
}
else //成功
{
if (FD_ISSET(fileno(stdin), &read_fd_set))
{
//得到缓冲区里有多少字节要被读取,然后将字节数放入nread里面
int length = 0;
ioctl(fileno(stdin), FIONREAD, &length);
cout << "stdin has " << length << " chars" << endl;
char buffer[1024] = { 0 };
length = read(fileno(stdin), buffer, length);
printf("data at stdin is available! ret=%d, read:%s\n"
, ret, buffer);
}
}
}
return 0;
}
上面的程序会循环等待用户输入,每当用户输入完毕,就会把用户的输入打印出来。
同时接着等待用户的输入:
3 实现定时器
每隔两秒钟程序输出一次
#include <stdio.h>
#include <stdlib.h>
#include <sys/select.h>
#include <iostream>
using namespace std;
int main(void)
{
fd_set rfds;
struct timeval tv;
int retval;
/* Watch stdin (fd 0) to see when it has input. */
FD_ZERO(&rfds);
FD_SET(0, &rfds);
/* Wait up to five seconds. */
tv.tv_sec = 2;
tv.tv_usec = 0;
while (true)
{
/*
select() may update the timeout argument to indicate how much time was left.
This implies that if it times out after 2 seconds it could set your tv_sec to 0.
If both of the fields of timeval are 0 it will return immediately.
*/
retval = select(1, nullptr, nullptr, nullptr, &tv);//only produce timeout signal
tv.tv_sec = 2;
/* Don't rely on the value of tv now! */
if (retval == -1)
perror("select()");
else if (retval)
printf("Data is available now.\n");
/* FD_ISSET(0, &rfds) will be true. */
else {
printf("No data within two seconds. ret=%d\n", retval);
}
}
return 0;
}
运行效果:
每隔两秒钟输出一行,中间就是敲回车作为输入,程序也不搭理,继续每隔两秒钟输出一次
4 生产者消费者
使用eventfd创建fd,使用select作为消费者等待生产者生产完成的工具
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h> //Definition of uint64_t
#include <pthread.h> //One thread writes to fd, other waits on it and then reads it
#include <time.h> //Writing thread uses delay before writing
#include <sys/eventfd.h>
#include <thread>
using namespace std;
int efd; //Event file descriptor
void writing_thread_func(void) {
ssize_t s;
printf("\n%s: now running...", __func__);
printf("\n%s: now sleeping for 2 seconds...", __func__);
fflush(stdout); //must call fflush before sleeping to ensure previous printf() is executed
sleep(2);
uint64_t product = 123456;
printf("\n%s: Writing %lld to eventfd...", __func__, product);
s = write(efd, &product, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
printf("\n%s: eventfd writing error. Exiting...", __func__);
exit(EXIT_FAILURE);
}
product = 111111;
fflush(stdout); //must call fflush before sleeping to ensure previous printf() is executed
sleep(2);
printf("\n%s: Writing %lld to eventfd...", __func__, product);
s = write(efd, &product, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
printf("\n%s: eventfd writing error. Exiting...", __func__);
exit(EXIT_FAILURE);
}
printf("\n%s: thread exiting...", __func__);
}
void reading_thread_func(void) {
ssize_t s;
uint64_t product_got;
int retval; //for select()
fd_set rfds; //for select()
struct timeval tv; //for select()
printf("\n%s: now running...", __func__);
printf("\n%s: now waiting on select()...", __func__);
//Watch efd
FD_ZERO(&rfds);
FD_SET(efd, &rfds);
//Wait up to 10 seconds
tv.tv_sec = 5;
tv.tv_usec = 0;
while (true)
{
retval = select(efd + 1, &rfds, NULL, NULL, &tv);
if (retval == -1) {
printf("\n%s: select() error. Exiting...", __func__);
exit(EXIT_FAILURE);
}
else if (retval > 0) {
printf("\n%s: select() says data is available now. ", __func__);
printf("\n%s: returned from select(), now executing read()...", __func__);
s = read(efd, &product_got, sizeof(uint64_t));
if (s != sizeof(uint64_t)) {
printf("\n%s: eventfd read error. Exiting...", __func__);
break;
}
printf("\n%s: Returned from read(), value read = %lld", __func__, product_got);
}
else if (retval == 0) {
printf("\n%s: select() says that no data was available even after 5 seconds...", __func__);
break;
}
}
printf("\n%s: thread exiting...", __func__);
}
int main() {
//Create eventfd
efd = eventfd(0, 0);
if (efd == -1) {
printf("\n%s: Unable to create eventfd! Exiting...", __func__);
exit(EXIT_FAILURE);
}
printf("\n%s: eventfd created. value = %d. Spawning threads...", __func__, efd);
//Create threads
std::thread writer_thread(writing_thread_func);
std::thread reader_thread(reading_thread_func);
writer_thread.join();
reader_thread.join();
//Wait for threads to terminate
printf("\n%s: closing eventfd. Exiting...", __func__);
close(efd);
exit(EXIT_SUCCESS);
}
程序运行输出:
全部源码下载:C加加辅导袁老师/learn-linux