Linux select入门

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

C++程序员Carea

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值