视频网站怎么做外链,二次开发什么意思,什么叫网站优化,仿牌外贸网站建设引言#xff1a;
北京时间#xff1a;2023/9/1/21:15#xff0c;下午刚更新完博客#xff0c;同理再接再厉#xff0c;这样整天不需要干什么#xff0c;除了玩手机的日子不多了#xff0c;马上就要开学#xff0c;每天需要签到签退的日子就要来临#xff0c;烦躁
北京时间2023/9/1/21:15下午刚更新完博客同理再接再厉这样整天不需要干什么除了玩手机的日子不多了马上就要开学每天需要签到签退的日子就要来临烦躁照我预料下学期我们学校应该会开一门Java的专业课现在这种线下课给我的第一感觉就是摆烂学了跟没学是一样的从上学期的MySql就能看出对于MySql而言目前就会一些简单的指令操作别的没有没有一种框架的感觉这就是线下课独有的魅力哈哈哈当然等我们在猴年之后把网络学完我们应该也就会进入MySql的学习此时的MySql是属于我们自己的MySql到时候肯定能领略到其的美丽嘻嘻然后就是《一念永恒》这本小说不知不觉间居然快追完了哎某些人别的本事没有看小说倒是挺上道此时心想如果能把看小说的时间挤出来拿去做题烦恼不就统统烟消云散了嘛哈哈哈乐观无所谓还是那句话时间咱还有慢慢搞该摆摆该烂烂咱不急开学再说呀呀呀开心还能耍。下面我们就正式进入该篇博客的学习有关服务端中日志和守护进程相关的知识。 深入服务端相关知识
在上篇博客中我们重点对TCP版本的套接字通信进行了原理分析和代码实现并在代码实现中我们分为了单执行流服务端和多执行流服务端的区分最后在博客尾部我们以多线程的方法来改进多进程方式下的服务端多执行流并在结尾提出使用线程池来进一步提高该服务端效率但因为服务端除了最关键的使用套接字进行网络通信之外对于服务端而言还有许多非常重要的组件当然对于上层应用层协议和下层TCP协议有关的知识或者组件目前我们先不了解我们此时就服务端而言先来简单看看其不可或缺的组件日志组件本质就是一个服务端代码执行过程的打印步骤在将其保存到特定文件中之后我们就能轻易的从该文件中定位到该服务端代码执行过程的错误位置以及错误信息进而便与我们改良。所以为了完善我们的服务端该篇博客我们就来学习一下有关日志的知识最后再将我们的服务端实现守护进程化具体下述详解。
服务端中的日志组件
首先强调对于目前的我们而言日志是一个基础知识所以我们只是简单的实现以及理解因为日志在大型项目中非常重要具体编写也较为复杂我们目前还没有具体的场景以及实例有待以后深入学习现在我们只需要简单看一看日志的大致实现过程以及具体内容就行。并且明白虽然日志没有我们想象的那么简单但是这是基于我们没有见过大型的实战项目而言对于日志本身而言如上述所说它只是一个程序执行过程中信息的打印而已。
为什么服务器中一定需要使用日志组件 讲日志相关知识我们就一定需要追本溯源本质就是搞懂因果关系因为什么所以什么到底为什么在上述中我们谈过了日志的本质就是在程序执行过程中在特定位置将我们想要获取的信息保存在特定的文件中然后从该文件中根据日志信息定位到程序的错误位置当然这就是我们在服务器中使用日志的目的但此时会有问题我为什么不直接使用cout或者printf直接将错误信息打印出来然后改善呢而是需要封装一个组件来获取日志信息呢本质两点原因首先如果我们直接在服务端代码中使用cout或者printf那么日志信息就会被直接打印到标准输出也就是控制台上那么此时就会涉及很强的IO过程加上如果该日志信息打印非常频繁的话最终就会导致该服务器的性能和运行速度被影响其次也就是我们需要将日志信息存储在一个特定的文件中所以为了避免代码冗余也就是多次进行将日志存储到文件的这一编码过程我们就需要使用日志组件每次调用该日志组件内的接口让其帮我们完成一系列日志存储工作。
封装日志组件预备知识 明白了上述知识此时我们就有了很强的目的性很强的抓手我们为什么要封装日志组件哦原来本质就是为了让其帮我们对特定信息进行存储有了这部分的认识此时就可以很好的引出我们接下来要讲的可变参数相关知识首先还是为什么需要认识可变参数呢通过上述的铺垫此时很好的就能明白因为我们需要利用日志组件头文件中对应的接口所以在调用接口时我们就需要自己对日志信息进行格式化控制类比使用printf所以谈到格式化控制我们就需要使用可变参数当然具体此时我们使用的是C语言中的可变参数而不是C中的可变参数包所以接下来我们就需要认识几个有意思的宏定义以及格式化控制接口如下所示 va_list 功能用于声明一个指向参数的指针变量所以该类型可以声明一个指针变量如va_list p在使用时需要对其进行初始化也就是让该参数指针指向某参数我们需要明确并且一般就是用于指向参数列表的第一个参数。 void va_start(va_list ap, last); 功能同理va_list中所说该宏用于初始化va_list声明的参数指针也就是让其指向对应参数列表的第一个参数第二个参数last表示函数参数中最后一个非省略运算符…的参数当然依据用法也就是我们需要格式化的字符串注意虽然我们没有直接将可变参数列表…传递给va_start接口 但是其会根据format参数last的位置和大小等信息来计算出可变参数列表的起始位置然后用于初始化ap。 type va_arg(va_list ap, type); 功能将参数指针当前指向参数列表中的参数依据format格式化信息中对应的字符转化为对应的类型如format中识别到d我们就将该参数转化为ints转化为字符指针c转化为字符同理此时以%为识别依据这也是为什么我们使用printf接口时需要使用%d/%s/%x的原因下文代码附上。第一个参数参数指针在该参数指针当前指向参数被转化为对应类型之后自动指向参数列表中的下一个可变参数第二个参数该参数对应类型。 void va_end(va_list ap); 功能关闭可变参数列表本质也就是销毁指向参数列表的指针。
注意上述宏定义都在头文件 strarg.h 中本质都是为了识别可变参数列表中对应参数类型而已具体va_arg识别过程如下代码所示 同理再次强调我们需要使用可变参数以及进行格式控制本质是因为我们需要自己实现日志组件中对应接口对服务端传过来的参数以及格式化信息进行控制也就是我们的日志组件需要有能力去处理服务端中想要获取的日志信息也就是对应参数表示的含义以及想要进行的格式化控制。当然根据上述代码可以看出我们对数据类型的控制比较麻烦所以这个过程我们一般不会自己进行编码而是直接使用对应的接口完成所以下面我们就来认识一下有关格式化控制的接口吧如下所示 int printf(const char *format, ...); 功能依据格式化数据以及参数列表将预期内容输出到标准输出文件中。第一个参数格式化字符串用于指定输出格式第二个参数省略运算符表示可变参数可以接收任意类型任意数据的参数提供格式化字符串中需要被输出参数的值。 int sprintf(char *str, const char *format, ...); 功能同理上述所说只不过此时是将数据输出到指定字符数组中。第一个参数字符指针用于接收字符数组的首元素地址数组名第二个参数同理格式化字符串第三个参数同理可变参数接收任意类型、数量的参数提供给格式化字符串使用。 int fprintf(FILE *stream, const char *format, ...); 功能同理将数据输出到指定文件中只不过在使用之前需要使用fopen接口以特定的方式打开某个指定文件然后获取该打开文件的返回值FILE* 类型的一个文件指针最后才能将格式化完成的数据成功写入该文件下述我们保存日志信息时就会使用到该接口。第一个参数FILE*的文件指针本质就是一个被打开文件底层是对open的封装内含缓冲区、文件描述符等… 本质就是向操作系统对应进程的文件描述符表申请了一个文件描述符而已此时再根据该文件的打开方式位运算判断来进行该文件数据读取或者写入。第二个参数同理第三个参数同理。 int snprintf(char *str, size_t size, const char *format, ...); 功能同理将数据输出到字符数组中只不过此时提供了更加安全的输出方式限制了输出字符的大小防止因为数据过大导致的溢出问题第一个参数同理字符指针用于指向字符数组的首元素地址注意本质是先有字符数组后有字符指针也就是本质是因为我们需要将数据存储到字符数组中所以此时使用字符指针来接收当然我们也可以是会用char str[]字符数组来接收第二个参数同理第三个参数同理。
这里简单对上述四个接口进行一次分析强调上述四个接口在我们的日志组件中是不可能被使用的本质还是那个道理我们需要的是自己实现一个日志打印接口所以服务端传过来的一定是需要进行格式化控制的信息和对应的参数所以我们自己的日志接口就一定需要是一个可变参数接口也就是使用了省略运算符的接口所以我们不能使用上述三个接口进行对可变参数列表的控制而必须使用下述四个接口如下所示 int vprintf(const char *format, va_list ap); 功能同理printf接口唯一区别最后一个参数此时不是省略运算符…的可变参数而是一个va_list 类型的参数指针用于存储可变参数列表。本质同理上述所说前者用于接收任意类型任意数量的参数后者用于存储接收到的这些任意类型任意数量的参数列表的第一个参数。 int vsprintf(char *str, const char *format, va_list ap); 功能同理sprintf接口唯一区别同理一个用于获取任意类型任意数量的参数一个用于存储获取到的任意类型任意数量的可变参数列表的第一个参数。 int vfprintf(FILE *stream, const char *format, va_list ap); 功能同理fprintf向某个被打开文件以某种方式写入数据同理唯一的区别就是一个用于获取任意类型任意数量的参数一个用于获取可变参数列表中第一个参数的地址第一个参数使用fopen接口打开之后的一个文件流第二个参数同理格式化字符串第三个参数同理。 int vsnprintf(char *str, size_t size, const char *format, va_list ap); 功能同理snprintf唯一区别同理参数同理。
同理所以此时我们应该使用上述四个接口来完成我们对参数列表的识别以及format的格式控制本质就是因为这四个接口的最后一个参数不是省略运算符而是va_list类型的参数指针也就意味着我们自己的接口中可以使用省略运算符…来接收服务端提供给我们的任意类型任意数量的参数 。
正式实现日志组件 现在搞定了上述有关C语言可变参数和对应格式控制接口相关的知识此时我们就可以正式进入日志组件的封装当然上述强调过我们目前只是简单了解目的就是为我们的服务端提供日志功能而已所以当我们学习完日志组件的实现之后我们就可以将我们上篇博客剩余的线程池实现服务端代码和日志组件结合在一起啦如下就是一个日志的简单实现 行文来到此处对于日志相关的知识我们就有了一个简单的认识啦剩余就是上篇博客欠下线程池版本服务端结合日志组件的这块知识当然在此再次强调上述我们实现的日志组件只是一个婴儿版的日志组件如果遇到大型项目我们一般使用的是专门的日志组件并且上述是经典的C语言实现代码具体C如何使用可变参数包实现感兴趣的小伙伴可以去了解接下来我们就正式来看看如何实现线程池版本的服务端并且使用日志组件存储日志信息。
线程池加日志组件版本服务端实现
有关线程池知识在当初系统中学习线程时我们有进行重点强调但是由于时间过去较久所以此时我们需要对相关知识进行一定的回顾在当时讲解线程池时我们重点对什么是池化技术资源管理方式什么是单例模式饿汉/懒汉进行了讲解最终利用饿汉模式封装了一份属于自己的线程池代码最终结合上述知识我们明白线程池的本质就是事先创建好一批线程然后在任务队列中有任务需要被执行的时候利用这一批线程去执行任务队列中对应的任务而已本质使用线程池的目的就是为了让其完成某种任务所以在接下来服务端使用线程池的过程中我们本质就只是将对应服务端需要执行的任务交给该线程池去完成而已当然此时我们使用的线程池就是我们之前对应封装的线程池如下图所示 在上图中我们就将服务端以线程池的方式实现并在对应场景下我们使用日志组件中对应的日志接口很好的将特定信息进行了保存所以有关服务端使用线程池以及日志组件实现的知识我们就了解完啦只不过接下来我们需要回顾一下对应代码的执行过程也就是上述我们是如何创建好任务然后用线程池单例对象执行该任务并且在线程池中线程是如何回调该任务具体如下图所示
ok搞定了上图有关线程池和日志实现服务端的知识我们就全部搞定多的没有全在图中认真看图就行再不行可以回顾我之前有关线程池的博客反正本质就是因为我们自己实现了线程库所以进行了两次线程回调函数的回调线程库回调线程池线程池回调任务类任务类再回调服务端看着挺复杂本质其实就是类的组合以及函数指针相关知识充分发现类的组合可以直接构造类然后加上函数值指针的这个用法真的非常好用在以后服务端需要实现更多功能的时候就可以直接封装成一个一个模块也就是一个一个类然后直接将对应服务端中的参数传过去再在类中利用这些参数我们就能让我们的服务端实现各种各样的功能啦
理解守护进程
当我们将一个服务端使用多执行流控制并且添加了池化技术以及日志组件那么该服务端在socket网络通信层面就基本较为完整了剩余有关上层序列化、反序列化、http协议等应用层方面知识我们将在下篇博客中具体了解接下来我们学习最后一个有关服务端的知识也就是守护进程及其相关知识同理对于一个新的概念想要快速入门以及掌握还是经典的两步走不是图解就是利用已学过知识进行对比或者延伸所以接下来我们就从两个方面来追本溯源彻底搞定守护进程相关知识。
什么是守护进程 首先单从名字来看守护进程一定是一个进程与我们之前在学习进程相关知识中的僵尸进程、孤儿进程、父子进程有一定的可对比性但为什么我们当时在系统中学习进程时没有讲解什么是守护进程呢同理因为在之前的学习中并没有特定的场景来供给我们学习守护进程当然也就是服务端场景而当此时我们有了服务端这个场景那么我们就可以对其进行学习但由于守护进程是一个全新的概念所以此时我们通过服务端与守护进程之间的关系我们先来简单介绍一下守护进程守护进程是操作系统中一个在后台独立运行的进程它不受其它进程和会话影响在系统运行期间持续运行。明白了守护进程的概念那么此时我们就很好的可以明白为什么服务端与我们的守护进程相关了本质就是想让服务端拥有守护进程的特性也就是对服务端进行守护进程化具体为什么需要让服务端守护进程化如下所述。
服务端为什么需要使用守护进程 明白了上述有关守护进程的介绍那么现在我们对于服务端和守护进程之间的关系就非常明确了本质就是想让服务端代码的执行过程不被其它进程和会话影响让服务端代码可以在系统后台执行运行。那么此时问题就来了为什么服务端代码有可能被其它进程或者会话影响呢所以想要搞懂这个问题也就是深入理解守护进程此时我们就需要引入几个其它的概念如前台进程/后台进程、进程组、会话、进程终端等…首先我们对前台进程和后台进程做一个对比这点虽然之前在学习进程有关知识时我们有了解过此时再来回顾一下明白前台进程与后台进程最大的区别就在于前台进程拥有终端的控制权也就是它可以向终端写入数据也可以获取终端中的数据所以它可以接收CtrlC或者CtrlZ这类的终止信号从而让某个前端进程终止反之因为后台进程与终端无直接联系所以它无法直接使用终端信号终止必须使用Kill指令进行终止。 最后明白对于一个程序而言它是前台进程还是后台进程这都是我们可以控制的如我们可以在程序后加上取地址符号用于表示该程序在后台执行并且在进程的状态属性中如果是S那么表示的就是前台进程S则表示后台进程明白这些知识之后此时如下图我们就从进程属性来深入理解守护进程相关知识吧 如上图所示当时我们在学习进程相关知识时我们学习了如何在Linux系统内部查找进程而在查找进程之前我们在后台运行了三个sleep进程并且让这三个进程处于等待状态所以当我们查找sleep进程之后我们就可以查找出正在后台等待的三个进程发现它们的父进程PPID都是27952也就是bash命令行解释器它们的进程编号PID分别是29803/30008/30014而它们的进程组编号PGID是29803/30008/30014从进程组编号可以发现进程组编号和PID编号相同所以从这点我们可以看出每一个进程它们自成一个进程组所以明白进程组不仅可以是多个进程也可以是只有一个进程同理也就是如果在父进程中创建了子进程那么父进程和子进程肯定属于同一个进程组或当同时运行多个进程时这些进程也同属于一个进程组而它们的SID会话编号可以发现与父进程PPID是相同的也就是说这三个进程不仅都是bash命令行解释器的子进程并且也同属于bash命令行解释器这个会话中具体下述提供一幅图解而它们的控制终端TTY同理表示的就是这三个进程它们使用的都是pts/2这个终端该终端一般在根目录下的dev目录中并且因为它们同属于27952bash会话中所以该终端本质也就是该bash所处的终端而对于终端而言它本质也就是一个文件而对于bash而言它本质就是Linux系统创建的一个会话进程并且分配对应的终端给其使用所以在bash命令行解释器中使用ls、touch、cd、rm等指令本质就是系统对对应指令进行处理处理完成之后将返回值写入到终端中也就是pts/2文件中最终我们在终端看到数据。而其中如果TTY控制终端为 那么表示的就是该进程与终端无关然后是它们的控制终端进程组IDTPGID本质也就是bash命令行解释器所处的进程组ID所以同理Linux系统在创建bash命令行解释器时可以是一个一个的创建也可以是多个同时创建然后分为不同的bash进程组本质就是一个套娃过程后面什么STAT、UID属性我们就不谈了直接来一幅图示让我们可以更好的理解bash命令行解释器与Linux系统之间的关系。 从上图我们就可以看出每次我们在使用远程登录软件登录Linux机器时远程Linux系统内部就会创建一个进程组任务这个进程组可以是只有一个进程也可以是多个进程然后让该进程组的组长进程会话首进程去执行命令行解释器相关代码让其成为bash进程专门负责处理用户输入的指令以及代码然后再创建对应的终端文件供给给bash命令行解释器让用户可以实现与bash进程的交互本质该终端文件有点类似于套接字文件本质就是用户将数据输入到该终端文件然后Linux服务端从该终端文件中获取数据处理数据最终将返回值再返回到该终端文件从而让用户在终端看到对应数据处理结果当然具体概念差异很大从功能层面分析而已。
总通过上述对进程属性以及图解的分析总结起来就是在Linux系统中我们可以使用多个会话一个会话表示的就是一个bash命令行解释器表示的就是一个进程组使用的就是一个终端文件其中就包含着不止一个进程进程组。
ok讲了这么多那我们不还是不知道为什么服务端需要使用守护进程吗别急哈哈哈下面让我们明白最后一个点有关进程组操作的知识明白完该知识之后我们就能搞懂为什么服务端一定要使用守护进程来实现啦在上述我们谈到有关前台进程和后台进程通过平时对bash命令行解释器的使用我们知道bash命令行解释器进程是一个前台进程因为它具有对应终端的控制权而如果当我们在终端通过bash运行一个其它前台进程那么我们会发现此时bash进程就会被终止前台开始运行新的程序此时对于bash命令行解释器来说它就被挂起成为了一个后台进程只有当我们终止正在运行进程此时bash进程才能重新变成前台进程供给用户使用所以明白对于终端而言当然也就是对于会话而言它只能同时运行一个前台进程系统中大部分进程都是以后台进程在运行所以接下来我们对后台进程的操作进行一个了解。
对后台进程进行操作 从上述我们明白在Linux系统中大部分的进程都是后台进程并且一个进程是允许进行前台进程和后台进程的切换的所以接下来我们就学习一下有关前后台进程的切换首先查看系统中所有的后台进程指令jobs当我们在系统后台运行了多个进程时如下图此时我们就能看到许多的后台进程。 从上图我们就可以看出当我们在系统后台运行了三个sleep暂停进程此时后台进程就会将该进程的进程组ID和后台进程编号返回给我们当我们使用jons查看所有后台进程时此时我们就看到了我们刚刚运行的后台进程而如果我们想让其中某个后台级进程从后台进程变为前台进程那么此时我们就可以使用指令fg 1/2/3fg 对应后台进程的编号所以当我们将某个后台进程变为了前台进程那么此时bash就会被挂起到后台此时程序执行被fg的后台进程同理此时我们就可以使用终端对被fg后台进程进行操作如CtrlC终止该fg后台进程或CtrlZ暂停该fg后台进程并且如果一个前台进程被暂停CtrlZ那么同理会被挂起到后台并显示其状态会暂停状态若想让其重新运行此时就可以使用指令bg所以以上操作流程就是后台进程的所以操作方法明白了这些之后此时我们对一个系统中的进程就有了很强的理解。所以此时我们就可以引出上述问题为什么服务端需要使用守护进程
铺垫完成正式回答服务端使用守护进程问题 无论是上述对进程属性中进程组ID会话ID终端控制等理解还是对前/后台进程操作的理解我们明白想要执行我们的服务端代码启动服务端当然也就是完成对应的任务那么我们就需要利用Linux系统分配的会话进程然后在该会话中去执行对应的任务并且该任务可以是一个前台任务也可以是一个后台任务但是如果当我不想使用该会话也就是退出Xshell或者是某个会话那么此时就有可能导致该会话内部的任务被影响同理会话进程组就是用来供给用户完成某些任务内含非常多的其它进程进程组当然如果正常理解我们关闭某个会话就是等同于关闭系统中的某个进程所以此时进程中的子进程自然就会被直接销毁当时由于系统的设计不同Windows/Linux所以关闭会话不一定就会将该会话中的进程销毁所以只能说是影响不能说是销毁但我们的服务端不容许被影响所以此时该问题就需要被解决解决方法很简单就是使用我们一直在强调的守护进程。本质也就是让我们后台运行的服务器不会被用户的登录、注销等操作影响用户需要在会话中启动服务端也就是让其自成一个会话不受其它会话的影响也就是让服务端从之前的包含关系变为并列关系会话这也就是我们让服务端守护进程化的根本原因。
服务端守护进程化代码实现
在自己实现守护进程之前我们首先需要明白系统中已经存在直接让服务端守护进程化的接口daemon 使用方法int daemon(int nochdir, int noclose); 其中第一个参数表示是否更改服务端的工作路径第二个参数表示是否更改服务端的标准输出、标准输入、标准错误文件描述符。明白了该接口之后此时我们自己对服务端守护进程化代码进行编写本质利用的是setsid接口同理daemon接口就是一个对setsid接口的封装只不过是进行了更加丰富的细节处理而已此时明白想要自己实现守护进程代码不仅只是使用setsid接口还需要进行几个方面的细节处理如我们需要将服务端的标准输入、标准输出、标准错误文件描述符关闭目的避免因为服务端在后台运行时服务端内部存在向终端标准输出打印从而影响用户的使用守护进程服务端自成一个会话拥有独立的终端还需要在服务端中忽略某些信号如SIGHUP/SIGINT/SIGPIPE这样可以避免我们在关闭服务端终端时系统向服务端发送某些信号从而导致服务器被终止同时也需要对服务端的工作路径做改变本质同理就是因为服务端被守护进程化那么它就是一个独立的会话此时它的工作路径就不再是原进程启动时的那个工作路径而是新会话中的某个进程工作路径所以此时当服务端需要使用原工作路径下的数据时就需要将其工作路径进行修改从新工作路径修改为服务端进程启动工作路径一个程序被启动它的工作路径就是当前目录路径最后想要让服务端实现守护进程化还需要确保调用setsid接口的进程不能是组长进程本质原理同理还是因为如果一个服务端被守护进程化那么它就拥有了自己的会话拥有了自己的终端所以如果让服务端的启动进程组长进程去执行setsid接口那么此时就会导致该进程同时存在于两个会话拥有两个终端这样是不合理的所以此时我们就需要让服务端启动进程创建一个子进程让子进程去执行setsid接口成为守护进程新会话的会首进程最终让服务端独立于所有会话。
明白了上述有关服务端守护进程实现的细节知识此时我们根据步骤就可以很好的在自己的代码中使用setsid接口封装属于自己的守护进程然后再提供给服务端使用啦具体如下图代码所示 在上述代码我们就很好的利用setsid接口对服务端的守护进程过程进行了封装对其中忽略信号、子进程作为话首进程、修改标准输入、输出、错误等过程我们就有了一个更深的认识并且通过对其分析可以看出守护进程的本质也是一种孤儿进程独立于所有进程只收到系统的管控所以以上就是守护进程的所有知识具体服务端只需要在初始化服务端之后运行上述Daemon接口此时服务端就会被守护进程化啦
总而言之结合守护进程是什么的概念和服务端持续运行的概念最后明白服务端与守护进程是不可分割的一个服务想要实现持续运行的效果那么它就需要被守护进程化具体过程如上述所说。
总结有关日志组件和守护进程的概念以及使用日志组件和守护进程实现服务端的知识就这样啦See you ⭐好书推荐 清华社【秋日阅读企划】领券立享优惠IT好书 5折叠加10元 无门槛优惠券即点即领 活动时间 9月4日-9月17日先到先得快快来抢
《C高性能编程》 【内容简介】
《C高性能编程》详细阐述了与C高性能编程相关的基本解决方案主要包括性能和并发性简介性能测量 CPU架构、资源和性能内存架构和性能线程、内存和并发并发和性能并发数据结构C中的并发高性能CC中的编译器优化未定义行为和性能性能设计等内容。此外本书还提供了相应的示例、代码以帮助读者进一步理解相关方案的实现过程。 本书适合作为高等院校计算机及相关专业的教材和教学参考书也可作为相关开发人员的自学用书和参考手册。 京东购买链接【C高性能编程】 当当购买链接【C高性能编程】