WebServer:log

news2024/9/21 1:48:37

超时锁的编写

这个问题处于blockqueue.h文件中,内容如下:

template<class T>
bool BlockDeque<T>::pop(T& item, int timeout) {
    std::unique_lock<std::mutex> locker(mtx_);
    while(deq_.empty()) {
        if(condConsumer_.wait_for(locker, std::chrono::seconds(timeout))
        == std::cv_status::timeout) {
            return false;
        }
        if(isClose_) {
            return false;
        }
    }
    item = deq_.front();
    deq_.pop_front();
    condProducer_.notify_one();
    return true;
}

在if的判断中,学习到了关于超时判定部分:

if(condConsumer_.wait_for(locker, std::chrono::seconds(timeout))
  == std::cv_status::timeout) {
	...
}

wait_for已经知道是循环等待了,这在之前关于C++多线程的笔记中有写,这里面有疑惑的主要是这个std::cv_status是什么东西。C++参考手册中有相应的内容:

enum class cv_status {
    no_timeout,
    timeout  
};

可以看到,它其实就是一个很简单的枚举类,用于判断是否超时。
查看有关wait_for相关的内容也可发现以下内容:
在这里插入图片描述

类的static关键字

我对这点有点忘记了,先描述一下static成员所具有的特点吧:

  1. 静态成员函数只能访问静态成员变量
  2. 静态成员变量不能够使用this指针,因为静态成员变量属于类而不属于类的实例
  3. 静态成员变量需要在类内声明,但是在类外初始化,如:
    class Temp {
    private:
    	static int num;
    };
    
    int Temp::num = 10;
    
    有几点我现在还是有点不是很理解:
    • 为什么在类外初始化的时候还是需要加上该变量的类型?就是说在我的想法中,由于在类内中我已经声明了这个变量Temp::num是int类型的,所以我在初始化的时候不应该再进行一个小的声明:
      Temp::num = 10;
      
    • 为什么一定要在类外初始化?(静态成员变量不能在类内初始化
  4. 静态成员在某种意义上和全局变量很相似,它的生命周期是整个程序的运行周期。

局部静态变量

局部静态变量同时具有局部变量静态变量的性质:

  1. 具有局部性:该变量只有在函数内部可使用
  2. 具有全局性:该变量的生命周期是程序的运行周期
  3. 静态:只会被初始化一次
void func() {
	static int num = 0;
	return num++;
}

int main() {
	cout << func() << endl;
	cout << func() << endl;
	cout << func() << endl;
}

通过运行这段简单的程序就能够理解了。

FILE类

这个项目中使用的是FILE,这个是C/C++官方提供的一个抽象接口,是比文件描述符fd更高一级的接口:

struct _IO_FILE;
typedef struct _IO_FILE FILE;

从源文件中只能找到这一步,再往上走关于_TO_FILE的定义我就没找到了。

C++参考手册,其中对FILE这个结构体进行了部分描述,由于该结构体是一个不透明的文件流,所以在参考手册中对其也没有很明确的描述,只需要怎么使用它就行了。
相关的常用函数如下:

FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *stream);
size_t fread(void *ptr, size_t size, size_t count, FILE *stream);
size_t fwrite(const void *ptr, size_t size, size_t count, FILE *stream);
int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
long ftell(FILE *stream);
int fseek(FILE *stream, long offset, int whence);
void rewind(FILE *stream);
int feof(FILE *stream);
int ferror(FILE *stream);
void clearerr(FILE *stream);

接下来给一段实例代码,用于展示FILE对文件的操作:

#include <stdio.h>

int main() {
    // 打开文件以进行写入
    FILE *file = fopen("example.txt", "w");
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }

    // 写入数据
    fprintf(file, "Hello, world!\n");
    fclose(file); // 关闭文件

    // 打开文件以进行读取
    file = fopen("example.txt", "r");
    if (file == NULL) {
        perror("Error opening file");
        return 1;
    }

    // 读取并打印数据
    char buffer[256];
    while (fgets(buffer, sizeof(buffer), file) != NULL) {
        printf("%s", buffer);
    }
    fclose(file); // 关闭文件

    return 0;
}

我觉得FILE有点难用(毕竟刚开始)

time_t

time_t通常用来存储自1970年1月1日00:00:00 UTC以来经过的秒数,通常需要转换为tm以便更好地进行表示
在以下代码中:

#include <ctime>

time_t timer = time(nullptr); // 用于获取当前时间
struct tm* sysTime = localtime(&timer); // 将time_t转换为tm格式
struct tm t = *sysTime;

time_t在探查之后发现它是一个long int类型,而tm才是我们坑看懂的类型。

time_t time(time_t *t); // 获取当前时间的time_t值
struct tm *localtime(const time_t *timep); // 将time_t转换为tm,表示为本地时间
struct tm *gmtime(const time_t *timep); // 将time_t转换为tm,表示为UTC时间

tm

time_t只是一个数字,用于表示秒数,这个数字我们人来看是不能直接读懂的,因此需要转换为人能读懂的格式,即:tm

struct tm
{
  int tm_sec;			/* Seconds.	[0-60] (1 leap second) */
  int tm_min;			/* Minutes.	[0-59] */
  int tm_hour;			/* Hours.	[0-23] */
  int tm_mday;			/* Day.		[1-31] */
  int tm_mon;			/* Month.	[0-11] */
  int tm_year;			/* Year	- 1900.  */
  int tm_wday;			/* Day of week.	[0-6] */
  int tm_yday;			/* Days in year.[0-365]	*/
  int tm_isdst;			/* DST.		[-1/0/1]*/

# ifdef	__USE_MISC
  long int tm_gmtoff;		/* Seconds east of UTC.  */
  const char *tm_zone;		/* Timezone abbreviation.  */
# else
  long int __tm_gmtoff;		/* Seconds east of UTC.  */
  const char *__tm_zone;	/* Timezone abbreviation.  */
# endif
};

而转换主要使用两个函数:

struct tm *localtime(const time_t *timep); // 将time_t转换为tm,表示为本地时间
struct tm *gmtime(const time_t *timep); // 将time_t转换为tm,表示为UTC时间

格式化字符串的使用

在使用snprintf的时候使用了以下格式化字符串:

"%s/%04d_%02d_%02d%s"

对这个我不是很懂,所以就查了下:

  • %s:这个很常用,字符串占位符,不多说了
  • %04d:%d都知道是表示的整数,%04d则是对这个整数还进行了一个约束:这个整数是四位数,若不是四位数在高位补0
  • %02d:类似与%04d

这里我们可以用一段简短的代码试一试:

#include <cstdio>

int main() {
    printf("%04d\n%4d", 1, 1);
}

这段代码中,两种占位符稍有不同:一种是04另一种就是4,后者的输出会保持四位,但是不会补0,而前者会补0

0001
   1

timeval

在上面使用了[[#time_t]],这里却又使用的是tiemval,这两个都是和时间相关的结构体,但是它们之间还是有区别的:

time_t是C标准库提供的
timeval是POSIX标准提出的

timeval的精度要高于time_t,前者可以达到微秒级,后者则是秒

#include <sys/time.h>

int settimeofday(const struct timeval *tv, const struct timezone *tz);
  • tv:用于接收时间的变量
  • tz:用于设置时区的变量(现已抛弃,直接传入nullptr就好)
struct timeval {
    time_t      tv_sec;  // 从1970年1月1日00:00:00 UTC到当前时间的秒数
    suseconds_t tv_usec; // 当前时间的微秒数
};

C语言的可变参数

这个是C语言的一种写法,C++的写法不太一样,有点类似于递归。
va_list的具体用法如下:

#include <stdio.h>
#include <stdarg.h>

// 自定义的函数,接受一个整数和可变数量的整数参数
void printNumbers(int count, ...) {
    va_list args;
    va_start(args, count);  // 初始化 va_list

    for (int i = 0; i < count; i++) {
        int num = va_arg(args, int);  // 访问下一个参数
        printf("%d ", num);
    }

    va_end(args);  // 清理 va_list
    printf("\n");
}

int main() {
    printNumbers(3, 1, 2, 3);        // 输出: 1 2 3
    printNumbers(5, 10, 20, 30, 40, 50);  // 输出: 10 20 30 40 50

    return 0;
}

其中的count表示的是该函数的最后一个固定参数。

上述代码是它的最基础使用,接下来详细说说stdarg.h的内容:

  • 声明一个va_list类型的变量,用于存储可变参数
  • va_start用于初始化上面声明的va_list
    void va_start(va_list ap, last);
    
    1. ap:va_start 将在这个变量中初始化可变参数的访问。
    2. last:这是最后一个固定参数的名称,va_start 用这个参数来确定可变参数列表的开始位置。
  • va_arg:用于访问可变参数
  • va_end:结束对va_list的访问(若是没有结束会引起资源泄漏问题

接下来再给一段更好理解的小程序:

#include <stdio.h>
#include <stdarg.h>

void temp(int last, ...) {
    va_list valist;
    va_start(valist, last);

    char msg[256] = {};
    
    vsnprintf(msg, 256, "%s, %s", valist);
    printf("%s", msg);

	va_end(valist);
}

int main() {
    temp(1, "hello", "world");
}

上i满这段代码使用了一个新的函数:vsnprintfsnprintf之前已经知道,就是用于格式化字符串,该函数同样是格式化字符串,只不过它传入的参数有va_list类型的,也就是说,它能够很好地处理可变参数的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2150792.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

内存泄漏

文章目录 内存泄漏发现问题topVisualVMArthas 原因分析代码层面并发请求 诊断问题MAT原理 –支配树获取运行时快照 内存泄漏 内存泄漏&#xff08;memory leak&#xff09;&#xff1a;在Java中如果不再使用一个对象&#xff0c;但是该对象依然在GC ROOT的引用链上&#xff0c;…

12.第二阶段x86游戏实战2-CE找基地址

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

全网最全:企业微信用户授权登录对接完整流程

Hello&#xff01;欢迎各位新老朋友来看小弟博客&#xff0c;祝大家事业顺利&#xff0c;财源广进&#xff01;&#xff01; 主题&#xff1a;企业微信用户授权与校验完整对接流程 一&#xff1a;构造第三方应用授权链接 如果第三方应用需要在打开的网页里面携带用户的身份信息…

吸尘器制造5G智能工厂物联数字孪生平台,推进制造业数字化转型

吸尘器制造行业&#xff0c;作为传统制造业的重要组成部分&#xff0c;也在积极探索如何通过先进技术实现生产模式的创新升级。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为吸尘器制造业的数字化转型铺设了一条高速通道&#xff0c;不仅极大地提升生产效率&#xff0…

华为---代理ARP简介及示例配置

目录 1. 概念 2. 前提条件 3. 使用环境 4. 工作过程 5. 优点 6. 缺点 7. 示例配置 7.1 示例场景 7.2基本配置 7.3 配置端口隔离 7.4 开启代理ARP 7.4.1 VLAN内代理ARP 7.4.2 VLAN间代理ARP 7.4.3路由式ARP代理 1. 概念 代理ARP&#xff08;Proxy ARP&#xff09;&…

GAMES202 作业1

参考&#xff1a;games202作业1 SM 首先是利用shadow map去生成尝试生成硬阴影。根据作业的要求 我们完成光源对物体的mvp矩阵 CalcLightMVP(translate, scale) {let lightMVP mat4.create();let modelMatrix mat4.create();let viewMatrix mat4.create();let projection…

Bigemap GIS Office 2024注册机 全能版地图下载软件

对于需要利用GIS信息进行编辑、设计的用户来说&#xff0c;Bigemap GIS Office占有重要地位。用户可以使用Bigemap GIS Office作为工具进行设计、分析、共享、管理和发布地理信息。Bigemap GIS Office能实现多种数据流转、嵌入、融合以及更多地为用户提供数据的增强处理及多种分…

文心一言 VS 讯飞星火 VS chatgpt (351)-- 算法导论24.1 2题

二、证明推论24.3。推论 24.3 的内容是设 G ( V , E ) G(V,E) G(V,E)是一带权重的源结点为 s s s的有向图&#xff0c;其权重函数为 ω : E → R ω:\boldsymbol{E→R} ω:E→R。假定图 G G G不包含从源结点 s s s可以到达的权重为负值的环路&#xff0c;则对于所有结点 v ∈ …

完美转发、C++11中与线程相关的std::ref

目录 模板中的万能引用 std::forward实现完美转发 C11中与线程相关的std::ref 线程函数参数 用函数指针作为线程函数 用lambda表达式作为线程函数 模板中的万能引用 void Func(int& x) {cout << "左值引用" << endl; } void Func(int&&am…

spark之不同序列化对比

一&#xff0c;spark的rdd的序列话不同介绍 下面是使用不同序列化后的占用资源和数据大小 2&#xff0c;sparksql中序列化的区别 sparksql中使用序列化和不使用差别不大&#xff0c;英文sparksql中默认使用了encode自己实现的序列化方法&#xff0c;加上与不加序列化差别不大…

基于PHP+MySQL组合开发的在线客服源码系统 聊天记录实时保存 带完整的安装代码包以及搭建部署教程

系统概述 随着互联网技术的飞速发展&#xff0c;企业与客户之间的沟通方式日益多样化&#xff0c;在线客服系统作为连接企业与客户的桥梁&#xff0c;其重要性不言而喻。然而&#xff0c;市场上现有的在线客服系统往往存在成本高、定制性差、维护复杂等问题。针对这些痛点&…

Zabbix 6.4添加中文语言

/usr/share/zabbix/include/locales .inc .phplocale -agrep “zh_CN" yum install langpacks-zh_CN.noarch y y y

【千帆AppBuilder】零代码+组件+代码节点方式实现AI应用《法定退休年龄计算器》

欢迎来到《小5讲堂》 这是《千帆》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 背景创建应用基本信息角色指令引导信息 组件整体界面开始节点代码节…

大腾智能3D协同平台通过华为云云软件认证

在数字化浪潮的推动下&#xff0c;工业软件不仅是研发和生产的核心工具&#xff0c;更是创新突破的基础&#xff0c;正成为推动工业领域数字化转型的关键力量。 近日&#xff0c;深圳市大腾信息技术有限公司凭借在技术创新与产品优化方面的卓越表现&#xff0c;再次迎来里程碑…

望繁信科技受邀出席ACS2023,为汽车行业数智化护航添翼

2023年5月25-26日&#xff0c;ACS2023第七届中国汽车数字科技峰会在上海成功举行。此次峰会汇聚了众多汽车领域的顶级专家、产业链代表及企业高管&#xff0c;共同探讨当今汽车产业的转型与未来发展趋势。 作为唯一受邀的流程挖掘厂商代表&#xff0c;望繁信科技携最新行业优势…

对于C++继承中子类与父类对象同时定义其析构顺序的探究

思考这样一串代码的运行结果&#xff1a; #include <iostream> using namespace std; class Person { public:~Person() { cout << "~Person()" << endl; } }; class Student:public Person { public:~Student() { cout << "~Student(…

【C++篇】C++类与对象深度解析(六):全面剖析拷贝省略、RVO、NRVO优化策略

文章目录 C类与对象前言读者须知RVO 与 NRVO 的启用条件如何确认优化是否启用&#xff1f; 1. 按值传递与拷贝省略1.1 按值传递的概念1.2 示例代码1.3 按值传递的性能影响1.3.1 完全不优化 1.4 不同编译器下的优化表现1.4.1 Visual Studio 2019普通优化1.4.2 Visual Studio 202…

828华为云征文|基于华为云Flexus X实例快速搭建Halo博客平台

目录 前言 一、Flexus云服务器X介绍 1.1 Flexus云服务器X实例简介 1.2 Flexus云服务器X实例特点 1.3 Flexus云服务器X实例场景需求 二、Flexus云服务器X购买 2.1 Flexus X实例购买 2.2 购买MySQL加速镜像 2.3 重置密码 2.4 登录服务器 三、Flexus X实例安装Docker 3.1 系统版本…

小小扑克牌算法

1.定义一个扑克牌类Card&#xff1a; package democard; public class Card {public String suit;//表示花色public int rank;//表示牌点数Overridepublic String toString() {return "{"suit rank"}";}//实例方法&#xff0c;初始化牌的点数和花色public…

IBM 撤出背后:国内技术人如何突围?

近年来&#xff0c;随着全球科技行业的风起云涌&#xff0c;各大科技巨头不断调整业务布局&#xff0c;甚至撤出某些市场。近日&#xff0c;IBM宣布在中国市场进一步收缩&#xff0c;引起了业界的广泛关注。作为曾经的科技领军企业&#xff0c;IBM的撤退背后到底传递出什么样的…