Administrator
发布于 2023-12-01 / 7 阅读 / 0 评论 / 0 点赞

TinyWebServer学习

目录

GitHub - qinguoyi/TinyWebServer: :fire: Linux下C++轻量级WebServer服务器 (githubfast.com)

01 线程同步机制封装类 (qq.com)

信号量

信号量是一种特殊的变量,有值SV,两种操作

P

若SV>0,则SV--

若SV==0,任务挂起

V

若有 等待SV挂起,则唤醒

若没有,SV++

SV就像资源,P消费,V生产

信号量的取值可以是任何自然数

  • sem_init函数用于初始化一个未命名的信号量

  • sem_destory函数用于销毁信号量

  • sem_wait函数将以原子操作方式将信号量减一,信号量为0时,sem_wait阻塞

  • sem_post函数以原子操作方式将信号量加一,信号量大于0时,唤醒调用sem_post的线程

互斥量

确保独占式访问,当进入关键代码段,获得互斥锁将其加锁;离开关键代码段,唤醒等待该互斥锁的线程.

  • pthread_mutex_init函数用于初始化互斥锁

  • pthread_mutex_destory函数用于销毁互斥锁

  • pthread_mutex_lock函数以原子操作方式给互斥锁加锁

  • pthread_mutex_unlock函数以原子操作方式给互斥锁解锁

条件变量

提供了一种线程间的通知机制,某个共享数据达到某个值时,唤醒等待这个共享数据的线程.

  • pthread_cond_init函数用于初始化条件变量

  • pthread_cond_destory函数销毁条件变量

  • pthread_cond_broadcast函数以广播的方式唤醒所有等待目标条件变量的线程

  • pthread_cond_wait函数用于等待目标条件变量.该函数调用时需要传入 mutex参数(加锁的互斥锁) ,函数执行时,先把调用线程放入条件变量的请求队列,然后将互斥锁mutex解锁,当函数成功返回为0时,互斥锁会再次被锁上. 也就是说函数内部会有一次解锁和加锁操作.

  •  pthread_cond_signal函数的作用是发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.如果没有线程处在阻塞等待状态,pthread_cond_signal也会成功返回。

      使用pthread_cond_signal一般不会有“惊群现象”产生,他最多只给一个线程发信号。假如有多个线程正在阻塞等待着这个条件变量的话,那么是根据各等待线程优先级的高低确定哪个线程接收到信号开始继续执行。如果各线程优先级相同,则根据等待时间的长短来确定哪个线程获得信号。但无论如何一个pthread_cond_signal调用最多发信一次。

封装锁

锁进行封装


 1class sem{
 2    public:
 3        //构造函数
 4        sem()
 5        {
 6            //信号量初始化
 7            if(sem_init(&m_sem,0,0)!=0){
 8                throw std::exception();
 9            }
10        }
11        //析构函数
12        ~sem()
13        {
14            //信号量销毁
15            sem_destroy(&m_sem);
16        }
17    private:
18        sem_t m_sem;
19};

  • 将重复使用的代码封装为函数,减少代码的重复,使其更简洁

 1   //条件变量的使用机制需要配合锁来使用
 2   //内部会有一次加锁和解锁
 3   //封装起来会使得更加简洁
 4   bool wait()
 5   {
 6       int ret=0;
 7       pthread_mutex_lock(&m_mutex);// 确保只有一个拿到锁,拿到锁的就是下个被唤醒的
 8       ret=pthread_cond_wait(&m_cond,&m_mutex);
 9       pthread_mutex_unlock(&m_mutex);
10       return ret==0;
11   }
12   bool signal()
13   {
14       return pthread_cond_signal(&m_cond)==0;//只唤醒一个
15   }

如果本文对你有帮助,阅读原文star一下服务器项目,我们需要你的星星^_^.

02 半同步半反应堆线程池(上) (qq.com)

服务器编程基本框架(3部分)

  • I/O单元

  • 逻辑单元

  • 网络存储单元

单元间通信通过请求队列进行通信

其中I/O单元用于处理客户端连接,读写网络数据;逻辑单元用于处理业务逻辑的线程;网络存储单元指本地数据库和文件等。

五种I/O模型

  • 阻塞IO:调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有没有返回,必须等这个函数返回才能进行下一步动作

  • 非阻塞IO:非阻塞等待,每隔一段时间就去检测IO事件是否就绪。没有就绪就可以做其他事。非阻塞I/O执行系统调用总是立即返回,不管时间是否已经发生,若时间没有发生,则返回-1,此时可以根据errno区分这两种情况,对于accept,recv和send,事件未发生时,errno通常被设置成eagain

  • 信号驱动IO:linux用套接口进行信号驱动IO,安装一个信号处理函数,进程继续运行并不阻塞,当IO时间就绪,进程收到SIGIO信号。然后处理IO事件。

  • IO复用:linux用select/poll函数实现IO复用模型,这两个函数也会使进程阻塞,但是和阻塞IO所不同的是这两个函数可以同时阻塞多个IO操作。而且可以同时对多个读操作、写操作的IO函数进行检测。知道有数据可读或可写时,才真正调用IO操作函数

  • 异步IO:linux中,可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。

注意:阻塞I/O,非阻塞I/O,信号驱动I/O和I/O复用都是同步I/O。同步I/O指内核向应用程序通知的是就绪事件,比如只通知有客户端连接,要求用户代码自行执行I/O操作,异步I/O是指内核向应用程序通知的是完成事件,比如读取客户端的数据后才通知应用程序,由内核完成I/O操作。

三分钟短文快速了解信号驱动式IO,似乎没那么完美 | IO | IT宅-arthinking's blog (itzhai.com)


评论