- 博客(85)
- 收藏
- 关注
原创 Linux中时序竞态问题
时序竞态产生原因首先来看一看pause()函数执行逻辑。函数原型:int pause(void);函数作用:进程调用pause函数时,会造成进程主动挂起(处于阻塞状态,并主动放弃CPU),并且等待信号将其唤醒。返回值:我们知道,信号的处理方式有三种:1. 默认动作;2. 忽略处理;3. 捕捉。进程收到一个信号后,会先处理响应信号,再唤醒pause函数。于是有下面几种情况:① 如果信号的默认处理动作是终止进程,则进程将被终止,也就是说一收到信号进程就终止了,pause函数根本就
2021-12-15 21:13:19
253
原创 Linux虚拟地址空间
CPU为什么 要用虚拟地址空间与物理地址空间映射?解决了什么样的问题?1.方便编译器和操作系统安排程序的地址分布。 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区;2.方便进程之间隔离 不同进程使用的虚拟地址彼此隔离,一个进程中的代码无法更改正在由另一进程使用的物理内存;3.方便OS使用可怜的内存 程序可以使用一些列虚拟地址来访问大于可用物理内存的内存缓冲区,当物理内存的供应量变小时,内存管理器会将物理内存页(通常大小为4kb)保存到磁盘文件。数据或...
2021-11-20 16:51:14
583
原创 Linux中共享库的制作和使用
共享库的制作1.命名规则lib + 名字 + .so2.制作步骤1)生成与位置无关的代码(生成与位置无关的.o,那么静态库是生成与位置有关的.o文件,因为制作静态库时,是将.o文件打包到静态库中,在虚拟内存中位置是固定的;而动态库只有在程序运行时,才会把动态库中的程序加载到虚拟内存的共享库区域中,而此位置是不固定的;2)将.o打包成共享库(动态库)3)发布和使用共享库4)解决程序执行时动态库无法被加载的问题a.放到系统的库目录中(/lib) —— 不允许使用.
2021-11-18 21:53:43
635
原创 Linux中静态库的制作和使用
Linux中静态库的制作1.命名规则1)lib + 库的名字 + .a;2)libmytest.a2.制作步骤1)生成对应的.o文件 — .c —— > .o -c2)将生成的.o文件打包 ar rcs + 静态库的名字(libmytest.a) + 生成的所有的.o3)发布和使用静态库:发布静态库和头文件即可首先建三个文件夹,分别存放头文件(include)、源文件(src)及生成的静态库文件(lib);head.hadd.cpp...
2021-11-17 22:09:36
1633
原创 Ubuntu使用apt-get upgrade升级时出错
今天在按照常规的sudo apt-get update更新软件列表后,再使用sudo apt-get upgrade升级软件时,出现了以下的错误:正在设置 linux-image-extra-4.4.0-97-generic (4.4.0-97.120) ...run-parts: executing /etc/kernel/postinst.d/apt-auto-removal 4.4.
2017-10-15 11:12:49
6913
3
转载 C/C++中volatile关键字详解
1.为什么用volatile?c/c++中的volatile关键字和const对应,用来修饰变量,通常用于建立语言级别的memory barrier。这是BS在“The C++ Programming Language”对volatile修饰词的说明:"A volatile specifier is a hint to a complier that an object may cha
2017-08-27 00:31:31
391
原创 经典动态规划问题总结
动态规划引入首先我们以一个最基本的例子来分析——菲波那切数列。我们都知道,菲波那切数列的递推公式f(n) = f(n-1)+f(n-2) (这里我就说明一般情况,不列举边界条件了),很简单,如果我们用递归的方法来求解f(n),两三行代码就出来了。那么我们深入分析一下这样有什么问题?f(2) = f(1) + f(0);f(3) = f(2) + f(1);f(4) = f(
2017-08-16 17:25:37
731
原创 环形链表插值
在一个环形单链表中插入一个值为val的结点,使得插入后的链表仍然有序。分析:我们设置两个指针,分别指向链表中的某一个结点和下一个结点,如果val的值在其中间,则将对应结点插入这两个结点中间,如果val的值比所有的结点值都大,则插入在头结点的前面,如果val的值比所有的值都小,则也插入在头结点前面,不过返回值应该是这个新的结点。//链表结构struct LinkList{ int
2017-08-09 08:46:31
521
原创 最长无重复字符子串
给定一个字符串,求出其最长的无重复的字符子串的长度。例:给定字符串str = “abcdahisjgdb”,则其最长无重复子串为“bcdahisjg”,长度为9。思路:我们遍历字符串,计算以每一个字符开头的所有无重复子串的长度,最后比较这些长度,找出最大的一个。在每一次的循环中,我们用哈希表来统计有无重复的字符。本题比较简单,直接上代码。code:int l
2017-08-07 20:47:36
500
原创 字符串拼接最小字典
给定一个字符串数组,找到一种拼接顺序,使得所有小字符串拼接成的大字符串在所有可能的拼接中字典序最小。例如:给定strArr = {"bac", "bd"},n = 2。则有两种拼接顺序bacbd和bdbac,显然第一种拼接的字典序要小于第二种。我们是否可以这样认为:如果str1的字典序小于str2的字典序,那么str1一定就放在前面,也就是str1+str2的字典序一定小于str2
2017-08-07 16:40:13
939
原创 字符串的移位
给定一个字符串str及其长度len,将其前面n个字符移动到字符串的尾部,将后面的(len-n)个字符串移动到字符串的前面。要求:算法的额外空间复杂度为O(1)。例:str = “ABCEF”,len = 5, n = 3,则移位后的字符串str = “EFABC”。思路:如果对空间复杂度没有要求,则我们可以将字符串看做两部分,然后开辟两块空间来存储,然后将两个子串调换位置即可,但是
2017-08-07 16:11:44
1921
原创 排序数组中的相邻两数最大差值
给定一个数组A及其大小n,求其排序后的相邻两数的最大差值。(注:要求时间复杂度为O(n))思路:题目要求对排序后的数组进行操作,显然需要先对数组进行排序。如果没有要求时间复杂度,那么可以有很多种排序算法,如快速排序、堆排序、归并排序等等。但是这里要求时间复杂度为O(n),就不能用上述常规的排序算法了。那么桶排序可以吗?由于我们不知道最大数的位数,因此,如果最大数的位数很大的话,我们
2017-08-07 10:45:06
2786
1
转载 Linux用户空间和内核空间详解
Linux驱动程序一般工作在内核空间,但也可以工作在用户空间。下面我们将详细解析什么是内核空间,什么是用户空间,以及如何判断它们。Linux简化了分段机制,使得虚拟地址与线性地址总是一致,因此,Linux的虚拟地址空间也为0~4G。Linux内核将这4G字节的地址空间分为两部分。将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),共内核使用,称为“内核空间”。而将较低的3
2017-07-21 10:52:41
548
原创 从给定数组中找出最大的两个数——二分递归
分析1:对于给定数组找出其中最大的两个数,很容易想到的就是遍历数组。首先遍历整个数组,找出最大的一个元素并记录下该位置;然后分别遍历该位置之前的区间和该位置之后的区间,分别找出这两个子区间的最大值,然后比较这两个子区间的最大值,大者即为整个数组的次大元素。显然,整个过程中,用到了三次for循环,算法的时间复杂度是比较大的,对于规模较小的数组尚且可以,但是当问题的规模非常大时,这种遍历的方法就不可行
2017-05-19 09:19:36
5223
原创 字符串中单词的逆转
实现字符串中单词的逆转,即将单词出现的顺序进行逆转。如将"Today is Friday!"逆转为"Friday! is Today"。思路:不使用额外空间完成,可以分为两步。首先将字符串全部逆转,比如:"Today is Friday!"逆转为"!yadirF si yadoT",然后通过空格分割单词,单词自身进行逆转。代码如下://Reverse实现一个字符串的全部
2017-05-16 09:09:10
1176
原创 牛课网--直通BAT面试算法精讲课--送优惠码啦
直通BAT面试算法精讲课专属优惠码:AqjvtPi。通过该优惠码报名,可立减10元! http://www.nowcoder.com/courses/1?coupon=AqjvtPi
2017-05-11 23:27:31
746
原创 字符串转换为数字
问题:输入一个表示整数的字符串,把该字符串转换成整数并输出。例如输入字符串“345”,则输出整数345。分析:可以一次扫描每一个字符,把之前得到的数字乘以10再加上当前字符表示的数字。需要考虑:1)输入的是否是空字符串; 2)是否有正负号; 3)字符串中是否有非数字的字符,如果有,则停止转换; 4)考虑移除问题;代码如下:int str2num(const
2017-05-11 22:15:55
524
转载 C++的运算符重载
C++中预定义的运算符的操作对象只能是基本数据类型。但实际上,对于许多用户自定义类型(例如类),也需要类似的运算操作。这时就必须在C++中重新定义这些运算符,赋予已有运算符新的功能,使它能够用于特定类型执行特定的操作。运算符重载的实质是函数重载,它提供了C++的可扩展性,也是C++最吸引人的特性之一。 运算符重载是通过创建运算符函数实现的,运算符函数定义了重载的运
2017-04-18 23:24:07
244
原创 IP地址类型
最初设计互联网络时,为了便于寻址以及层次化构造网络,每个IP地址包括两个标识码(ID),即网络ID和主机ID。同一个物理网络上的所有主机都使用同一个网络ID,网络上的一个主机(包括网络上工作站,服务器和路由器等)有一个主机ID与其对应。IP地址根据网络ID的不同分为5种类型,A类地址、B类地址、C类地址、D类地址和E类地址。1.A类地址一个A类IP地址由1字节的网络地址和3字节主机地址组成
2017-04-14 08:56:36
745
原创 字符串—空格替换
题目:请实现一个函数,把字符串中的每个空格图化成“%20”。例如输入“We are happy.”,则输出“We%20are%20happy.”。分析:有两种情形。一种是直接在原来的字符串上进行修改,从头到尾依次遍历每一个字符,当遇到空格时,我们就用“%20”去替换该空格,由于字符串长度的增加,每一次的替换,空格后的字符串都要向后移动,该做法的复杂度为O(n2);另一种是创建一个新的字符串,并
2017-04-12 15:14:01
557
原创 二维数组中的查找
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。分析:按照常规思路,我们对数组中的每一个数进行遍历,那么复杂度是比较大的,为O(n2)。显然,这种做法不仅效率低下,而且没有用到题目中给的数组递增的信息。那么怎么运用数组递增的信息呢?可以这样想:假如我们每次选取数组的右上角
2017-04-12 12:29:49
342
原创 进程间的通信
进程通信是指进程之间的信息交换。PV操作是低级通信方式,高级通信方式是指以较高的效率传输大量数据的通信方式。高级通信方法主要有以下三类。共享存储在通信的进程之间存在一块可以直接访问的共享空间,通过对这片共享空间进行写/读操作实现进程之间的信息交换。在对共享空间进行写/读操作时,需要使用同步互斥工具(如P操作、V操作),对共享空间的写/读进行控制。共享存储又分为两种:低级方式的共享是基于数据
2017-04-05 10:35:20
1106
原创 keepalive、pipe、lingering_close
本篇介绍一下nginx中一个http请求相关的概念—keepalive。在nginx中,对于http1.0与http1.1也是支持长连接的。什么是长连接呢?我们知道,http请求是基于TCP协议之上的,那么,当客户端在发起请求前,需要先与服务端建立TCP连接,而每一次的TCP连接是需要三次握手来确定的,如果客户端与服务端之间网络差一点,这三次交互消费的时间会比较多,而且三次交互也会带来
2017-03-30 11:38:39
689
原创 SIGPIPE信号
SIGPIPE信号详解当服务器端kill掉一个已连接的子进程时(也就是close一个连接),如果客户端不理会 该操作,反而写入更多的数据到服务器上,会发生什么呢?这种情况是可能发生的,举例来说,客户可能在读回任何数据之前执行两次针对服务器的写操作,而RST是由其中第一次写操作引发的。适用于此的规则是:当一个进程向某个已收到RST的套接字执行写操作时,内核向该进程发送一个SIGPIPE信号。
2017-03-28 16:00:14
1264
原创 bind函数—绑定地址和端口
在调用bind函数是,可以指定一个端口号,或指定一个IP地址,也可以两者都指定,还可以都不指定。服务器在启动时捆绑它们的众所周知端口。如果一个TCP客户或服务器未曾调用bind捆绑一个端口,当调用connect或listen时,内核就要为相应的套接字选择一个临时端口。让内核来选择临时端口对于TCP客户来说是正常的,除非应用需要一个预留端口;然而对于TCP服务器来说却极为罕见,因为服务器
2017-03-27 22:11:22
10327
原创 线程同步—条件变量和信号量
上一节提到了线程互斥和同步的概念,并且给出了两种用于解决共享资源互斥的利器:互斥锁和读写锁。那么本节将介绍两种用于解决线程同步的概念:条件变量和信号量。一. 条件变量1.基本概念互斥锁的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。条件变量的内部实质上是一个等待队列,放置等待(阻塞)的线程,线程在条件变量上等待和
2017-03-24 11:40:44
1942
原创 函数不能传递动态内存
下面这道面试题是有关指针、动态内存分配的相关内容,感觉比较经典,记录下来大家共享。问题:What will happen after running the "Test"?#include using namespace std;void GetMemory(char* p, int num){ p = (char*)malloc(sizeof(char*)num);};
2017-03-20 11:51:34
2304
5
原创 用select改进回射客户-服务器模型
这一节主要来说一下如何用select函数来改进我们前面的客户端-服务器模型。前面我们在处理多客户端模型时,每当连接一个客户端时,服务器端就需要开辟一个新的进程来处理新的客户端,这样就会耗费很大的内存资源。而select函数允许进程指示内核等待多个事件中的任何一个发生,并只有在有一个或多个事件事件发生或经历一段指定的时间后才唤醒它。或者说select具有管理多个I/O的能力,对于多个套接口,
2017-03-05 15:46:24
472
原创 回射客户-服务器模型(4)
由于TCP是一种基于字节流的传输,属于无边界传输,所以它不能够处理消息与消息之间的边界问题,因此存在粘包问题。如下图所示:M1和M2是从主机A传送到主机B的两条消息,那么中间可能有几种传输情况:a. 两条消息刚好分别完整的传输;b. 先传输M1和M2的一部分,然后M2的另一部分单独传输;c. 先传输M1的一部分,然后M1的另一部分和M2一起传输;粘包产生的原
2017-03-05 11:59:14
405
原创 回射客户-服务器模型(3)
前面连接的C/S模型只是单方面的客户端发送数据,服务器端接收数据。那么本节将根据前两节已有的经验知识来实现一个简单的点对点聊天程序。注:这里只实现了以个服务器与一个客户端的相互收发数据。下面这篇文章对整个回射客户服务器的模型建立过程有一个说明,我这里就不再做过多讲解。由于刚刚接触网络编程,中间可能会有纰漏,还请大家多多指正。点击打开链接服务器端:p2psrv.c#inclu
2017-02-25 21:15:08
312
原创 回射客户-服务器模型(2)
在上一节“回射客户-服务器模型(1)”中存在下面几个问题。1.就是当服务器断开再立即重新开启时,需要重新绑定地址,而此时的服务器处于TIME_WAIT状态,在这种状态下,它是无法立即重新绑定的。那么这种情况下,我们可以使用REUSEADDR这个选项来解决这个问题。使用REUSEADDR选项就可以不必等待TIME_WAIT状态消失就可以立即重启服务器。我们只需在服务器端的代码中使
2017-02-24 15:55:54
505
原创 回射客户-服务器模型(1)
最近在学习socket编程,根据自己的学习过程及学习笔记,下面来梳理一下如何实现一个简单的回射客户-服务器模型,也借此来熟悉一下socket、bind、listen、accept、connect这些函数的使用。下面先看一下一个客户/服务器模型的框架图。可以看到,服务器创建过程一般是:1)创建套接字,使用socket函数,这个时候的套接字是主动套接字;2)初始化服务器
2017-02-23 23:55:23
794
原创 类对象作为函数参数
网上看见一段代码,是关于类对象作为函数的参数,其中有几点知识,贴出来大家一起学习。直接来看代码:#include #include using namespace std;class people {private: char *name; int age;public: people(char *namestr,int i); ~people(); char *
2017-02-21 21:02:14
11973
1
原创 TCP传输的可靠性及滑动窗口协议
TCP不可靠的表现: 出错——通过校验和解决; 丢包——超时重传+确认机制解决; 失序、重复——通过TCP头部的序号解决;TCP如何保证传输的可靠性?1.应用数据被分割成TCP认为最合适发送的数据块,称为段,传递给IP层。2.当TCP发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。(超时重传)3
2017-02-21 19:54:56
1958
原创 线程互斥——互斥锁与读写锁
一. 线程同步与互斥概念 1. 线程同步是一个宏观概念,在微观上包含线程的相互排斥和线程先后执行的约束问题;解决同步方式:条件变量和线程信号量; 2. 线程互斥线程执行的相互排斥;解决互斥方式:互斥锁、读写锁和线程信号; 3. 说明 1)线程的同步与互斥主要是用于解决共享资源的安全性问题; 2)线程同步与
2017-01-17 15:29:46
764
原创 线程的状态及其相互转换
线程从创建、运行到结束总是处于下面五个状态之一:新建状态、就绪状态、运行状态、阻塞状态以及死亡状态。其中,阻塞状态会因为不同的原因而产生的,所以根据不同的阻塞状态,线程的状态转换图又可以细化如下:注意:要从Blocked状态转换到Running状态,必须先从Blocked转换到Runnable。1. 新建状态2. 就绪状态3.运行状态
2017-01-17 10:17:17
586
原创 线程的清理、控制以及线程属性的概念
一. 线程清理和控制函数如同进程可以调用atexit函数安排在它退出时需要调用的函数一样,线程也可以安排在它退出时执行一些函数。这些清理函数记录在栈中,所以它们执行的顺序和注册的顺序是相反的。#include void pthread_cleanup_push(void(*rtn)(void*), void *arg);void pthread_cleanup_pop(int ex
2017-01-16 16:16:36
459
原创 线程的创建和终止
一. 线程的创建#include int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start rtn)(void*), void *restrict arg);返回:成功返回0,否则返
2017-01-15 23:06:02
1229
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人