C / C ++ interview questions summary

First talk about these things, some must master, when you speak out some interviews that shine. Hold their own. Mishandled all get to know. It is not backing down.

First: the foundation (must be familiar to the heart)

1.  const keyword (antonyms mutable)

Must be initialized when (1) the definition of

(2) may be a pointer to a pointer const, it may be a pointer to an object pointer to a const

(3) a parameter defined as const, can not be modified in vivo function

(4) behind the increase Const, indicating that the member function does not modify the class member variables. It is essentially a modified hidden * this pointer. Plus const member functions can be const or non-const object to call, but an ordinary member function (const without modification) can only be ordinary objects (no const qualifier) ​​call.

(5) preceded by const, const represents the return value is of type

(6) Const modified when a member variable can not be initialized in the declaration, the list must be initialized in the constructor's

2.  static keyword

(1) in the function, a static variable whose value is maintained unchanged during this function is called

(2) (not in function), it may be a static variable of all modules in the module access functions, but can not be accessed by other functions outside the module.

(3) in the module, a static function can only be called by other functions within this module.

(4) static member variable class belongs to the class can not be defined within the class, the class can be defined in the scope.

(. 5) in the static member function belongs to the class does not contain this pointer, only call static member functions.

(6) static global variables can only be used in this document, limiting its scope; ordinary global variables can be used in other documents.

(7) static local variables must be initialized, ordinary local variables need not; where the former function is called multiple times when, on the basis of a result of calculation, while the latter function is called is located, or the original value. Although static local variable persists after the end of the function call, but other functions can not reference it.

(8) static function is defined in this document, while other files can be aware of its existence, but not; extern ordinary default function, the other files can also be used. Static function has two advantages: First, other files can define functions with the same name, not conflict; the second is a static function can not be used for other functions.

3.  extern keyword

(1) extern C, indicating that the segment code in C language compiled.

(2) extern placed in front of a variable or function, indicating that the variable or function is defined in another file, suggesting that the compiler to find other modules defined, equivalent to the former statement.

4. The  difference between the pointers and references

(1) reference is direct access pointer is accessed indirectly.

(2) reference is an alias variable itself does not allocate its own memory space alone, has its own memory pointer

(3) reference binding memory space (must initial value), is a variable alias can not change the binding, you can change the value of the object.

In general: the efficiency of both a reference pointer, with the convenience of use and intuitiveness of variables

5.explicit is used to do?
Declared as explicit constructor can not be used in an implicit conversion. Can block should not be allowed to go through the conversion constructor occurs implicit conversion is performed.

6. inline usage

https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html

 

7. There are some keywords can not remember a time, and have time to finish it.

 

The second: C ++ in memory

1.  The difference between new / delete and malloc / free?

(1) malloc / free standard library function is C / C ++ language, new / delete the C ++ operator
(2) new space can be automatically assigned, malloc passed parameters.
(3) new / delete an object is able to call the constructor and destructor memory further more detailed work, and malloc / free not.
Since the new / delete functions completely covered malloc / free, Why C ++ also retained malloc / free do? Because C ++ programs often have to call C functions, while the C program can only use malloc / free dynamic memory management.

2.  shallow copy and deep copy? Why use a deep copy?

(1) shallow copy char * arr [] = "hello"; char * a = arr; shallow copy just copy the pointer, two pointers pointing to the copy of the same memory space.

(2) a deep copy char * arr [] = "hello"; char * a = new char []; a = arr; deep copy of only a pointer is copied, but also a pointer to the content copy, after the deep copy of the pointer is a pointer to two different addresses.

Shallow copy problems occur: (1) a shallow copy just copies the pointer, so that the two pointers point to the same address, so that at the end of the object destructor is called, can cause destruction twice with a resource that delete the same piece of memory twice, resulting in program crashes; (2) such that the two shallow copy a pointer to the same address, any changes will affect the other one; (3) with a space, the second release failure supervisor able to operate the space, resulting in memory leaks.

3 . In-depth talk about the heap and stack ?

(1) different allocation and management:
       heap is dynamically allocated, the allocation and its space is released by the programmer control.
      Stack Manager automatically by the compiler. There are two stacks of distribution: static allocation and dynamic allocation. Static assignment is done by the compiler, such as the allocation of local variables. Dynamically allocated by alloca () function is assigned, but the dynamic allocation and heap stack are different, it is dynamically assigned and released without manual control by the compiler.
(2) different fragmentation
        heap, the frequent new / delete or malloc / free will inevitably lead to discontinuity of memory space, causing a lot of debris, so reducing the efficiency of the procedure.
        On the stack, the fragmentation is not an issue, because the stack is a last-out queue, never had a memory block pop-up from the middle of the stack.
(3) the growth direction different from
      the stack memory address is increased toward a direction of growth, increase from the low to the high address memory the address direction.
     The stack is reduced in the direction of growth of the memory address, the memory address by a high growth to lower addresses.

60. The difference between the static allocation and dynamic memory allocation?

Different (1) time. Static allocation occurs when the program is compiled and linked. Dynamic allocation occurs when the program transferred and executed.
(2) different space. Heap is allocated dynamically, not statically allocated heap. There are two kinds of stack allocation: static allocation and dynamic allocation. Static allocation is done compiler, such as the allocation of local variables. alloca, you can dynamically allocate memory from the stack, do not worry about memory leaks, when the function returns, the memory by alloca application will be automatically released.

Part III: class, inheritance, polymorphism

1. The  realization of the string class

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

class string

{

public

String()    //初始化

: _pstr(new char[1])

{}

 

String(const char * pstr );     //普通构造函数

: _pstr(new char[strlen(pstr) + 1]())

{

  strcpy(_pstr,pstr);

}

 

String(const String & rhs); //复制构造函数

: _pstr(new char[strlen(pstr) + 1]())

{

  strcpy(_pstr, rhs.pstr);

}

 

String(String && rhs);  //移动构造函数,右值引用

: _pstr(rhs._pstr)

{

  rhs.pstr = NULL;

}

 

String & operator=(const String & rhs)  //重载复制运算符函数

{

  if(this != & rhs)

  {

    delete [] _pstr;

    _pstr = new char[strlen(rhs._pstr) + 1]();

    strcpy(_pstr, rhs._pstr);

  }

  return *this;

}

String & operator=(String && rhs) //移动赋值运算符函数

{

  if(this != &rhs)

  {

    delete [] _pstr;

    _pstr = rhs._pstr;

    rhs._pstr = NULL;

  }

  return this;

}

 

~String()

{

  delete [] _pstr;

}

 

  friend std::ostream &operator<<(std::ostream & os, const String & rhs);

private:

  char * _pstr;

};

 

std::ostream & operator<<(std::ostream & os, const String & rhs)

{

  os << rhs._pstr;

  return os;

}

2. 什么是继承?什么是多态?

(1)

(2)C++中多态机制主要体现在两个方面,一个是函数的重载,一个是接口的重写。接口多态指的是“一个接口多种形态”。每一个对象内部都有一个虚表指针,该虚表指针被初始化为本类的虚表。所以在程序中,不管你的对象类型如何转换,但该对象内部的虚表指针是固定的,所以呢,才能实现动态的对象函数调用,这就是C++多态性实现的原理。

多态的基础是继承,需要虚函数的支持,简单的多态是很简单的。子类继承父类大部分的资源,不能继承的有构造函数,析构函数,拷贝构造函数,operator=函数,友元函数等等

多态作用:

隐藏实现细节,代码能够模块化;2. 接口重用:为了类在继承和派生的时候正确调用。

多态的两个必要条件:

1. 一个基类的指针或者引用指向派生类的对象;2.虚函数

 

3. 什么是静态关联?什么是动态关联?

静态关联是程序在编译阶段就能确定实际执行动作,程序运行时才能确定执行的动作叫动态关联。

4. 虚函数是如何实现的?

编译时若基类中有虚函数,编译器为该的类创建一个一维数组的虚表,存放是每个虚函数的地址。基类和派生类都包含虚函数时,这两个类都建立一个虚表。构造函数中进行虚表的创建和虚表指针的初始化。在构造子类对象时,要先调用父类的构造函数,初始化父类对象的虚表指针,该虚表指针指向父类的虚表。执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的虚表。每一个类都有虚表。虚表可以继承,如果子类没有重写虚函数,那么子类虚表中仍然会有该函数的地址,只不过这个地址指向的是基类的虚函数实现。派生类的虚表中虚函数地址的排列顺序和基类的虚表中虚函数地址排列顺序相同。当用一个指针/引用调用一个函数的时候,被调用的函数是取决于这个指针/引用的类型。即如果这个指针/引用是基类对象的指针/引用就调用基类的方法;如果指针/引用是派生类对象的指针/引用就调用派生类的方法,当然如果派生类中没有此方法,就会向上到基类里面去寻找相应的方法。这些调用在编译阶段就确定了。当涉及到多态性的时候,采用了虚函数和动态绑定,此时的调用就不会在编译时候确定而是在运行时确定。不在单独考虑指针/引用的类型而是看指针/引用的对象的类型来判断函数的调用,根据对象中虚指针指向的虚表中的函数的地址来确定调用哪个函数。

5. 虚函数与纯虚函数的区别?含有纯虚函数的类叫什么?

(1)虚函数与纯虚函数都可以在子类中重写。

(2)纯虚函数只有定义,没有实现;虚函数既要有定义,也要有实现的代码。

(3)纯虚函数 vritual void print() = 0; 虚函数 vritual void print() {  XXX  };

(4)包含纯虚函数的类叫抽象类,该类不可以创建对象;而含有虚函数的类可以创建对象。

6. 多重继承如何解决?

虚拟继承解决了多重继承的问题。如:A是基类,B、C继承自A,D多重继承自B和C,那么D访问A中的变量时,就会出现二义性错误。如果类B和类C虚拟继承自A,那么类D只会有A的一个对象,这样就解决了二义性问题。或者用成员限定符解决二义性。

7. 派生类与虚函数概述

(1)派生类继承的函数不能定义为虚函数。虚函数是希望派生类重新定义。如果派生类没有重新定义某个虚函数,则在调用的时候会使用基类中定义的版本。

(2)派生类中函数的声明必须与基类中定义的方式完全匹配。

(3)基类中声明为虚函数,则派生类也为虚函数。

8. 为什么析构函数要定义为虚函数?哪些函数不能是虚函数?

(1)如果析构函数不是虚函数,那么释放内存时候,编译器会使用静态联编,认为p就是一个基类指针,调用基类析构函数,这样子类对象的内存没有释放,造成内存泄漏。定义成虚函数以后,就会动态联编,先调用子类析构函数,再基类。
(2)1)普通函数只能重载,不能被重写,因此编译器会在编译时绑定函数。
2)构造函数是知道全部信息才能创建对象,然而虚函数允许只知道部分信息。
3)内联函数在编译时被展开,虚函数在运行时才能动态绑定函数。
4)友元函数 因为不可以被继承。
5)静态成员函数 只有一个实体,不能被继承。父类和子类共有。

 

9. 析构函数可以抛出异常吗?为什么不能抛出异常?除了资源泄露,还有其他需考虑的因素吗?

C++标准指明析构函数不能、也不应该抛出异常。C++异常处理模型最大的特点和优势就是对C++中的面向对象提供了最强大的无缝支持。那么如果对象在运行期间出现了异常,C++异常处理模型有责任清除那些由于出现异常所导致的已经失效了的对象(也即对象超出了它原来的作用域),并释放对象原来所分配的资源, 这就是调用这些对象的析构函数来完成释放资源的任务,所以从这个意义上说,析构函数已经变成了异常处理的一部分。

1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。

2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题。

11.动态链接库的两种使用方法及特点?

1).载入时动态链接,模块非常明确调用某个导出函数,使得他们就像本地函数一样。这需要链接时链接那些函数所在DLL的导入库,导入库向系统提供了载入DLL时所需的信息及DLL函数定位。 

2)运行时动态链接。

 

 

第四篇:STL

1. STL各类容器(3个顺序+4个关联+1个无序关联)的实现原理及使用情形

(1)vector:可变数组大小。支持快速随机访问。在尾部之外的位置插入或删除元素可能很慢。

(2)deque:双端队列。支持快速随机访问。在头尾插入或删除碎度很快。

(3)list:双向链表。只支持双向顺序访问。在list的任何位置进行插入或删除操作速度都很快。

(4)set/multiset:只有键值,可以把set当做集合使用。multiset可以存放相同的元素,set只能存放不同的元素。

(5)map/multimap:键值对,每一个元素都是pair,pair的第一个元素是关键字,第二个元素是值。这两者的区别就在于multimap可以存放多个相同的关键字,map则不可以。

(3)与(5)的底层实现都是红黑树,动态平衡二叉树。插入和删除等操作的时间复杂度是O(logn)(6)中的底层实现是哈希函数。

(6)unordered_map 映射 
unordered_multimap 多重映射 
unordered_set 集合 
unordered_multiset 多重集合

  1. 什么是STL?(面试主要是深入某个点问你)

 六大组件:容器、迭代器、适配器、算法、函数对象、配置器(透明)

(1)容器(略,自己看)

(2)迭代器:随机访问迭代器(Random Access Iterator)

双向迭代器(Bidirectional Iterator)

前向迭代器(Forward Iterator)

输入迭代器(Input Iterator)

输出迭代器(Output Iterator)

(3)适配器就是Interface(接口),对容器、迭代器和算法进行包装,但其实质还是容器、迭代器和算法,只是不依赖于具体的标准容器、迭代器和算法类型,容器适配器可以理解为容器的模板,迭代器适配器可理解为迭代器的模板,算法适配器可理解为算法的模板。

常见的容器适配器有:stack、queue、priority_queue(不支持迭代器访问)

前面简要提到了适配器的概念,适配器相当于提供了一个接口,使得某些不适用于特定对象的方法可以被该对象所用,适配器形象的功能图解如所示,图中,容器或函数对象无法直接应用于算法,因此,必须有一种中间过渡机制来实现两者的匹配,这就是适配器,本质上,适配器是使一事物的行为类似于另一事物的行为的一种机制。

(4)STL将算法库分为4组,前3个在algorithm头文件中描述,而第4个在numeric头文件中描述:

非修改式序列操作:不改变容器的内容,如find()、for_each()等。

修改式序列操作:可以修改容器中的内容,如transform()、random_shuffle()、copy等。

排序和相关操作:包括各种排序函数等,如sort()等。

通用数字运算:计算两个容器的内部乘积等。

(5)函数对象是可以以函数方式与()结合使用的任意对象,包括:(functor-仿函数)

函数名;指向函数的指针;重载了()操作符的类对象(即定义了函数operator()()的类)。

(6)一级配置器和二级配置器

空间配置器,就是用来配置、管理和释放空间的,给所有的容器包括算法提供生存空间。

作用:

(1)提高代码复用率,功能模块化。 
(2)减少内存碎片问题。 
(3)提高内存分配的效率。 
(4)有内存不足时的应对措施。 
(5)隐藏实际中对存储空间的分配及释放细节,确保所有被分配的存储空间都最终获得释放。 
(5)考虑多线程状态。

考虑到小型区块可能导致的内存碎片问题,设置了两级空间配置器。分别为:一级空间配置器、二级空间配置器。当区块大于128字节,调用一级空间配置器;小于等于128字节,为了降低额外开销,用底层较复杂的二级空间配置器。

 

一级空间配置器

用malloc()、free()、realloc()等C函数执行内存配置、释放、重配置操作,并实现出类似的C++new_hanle的机制

 

二级空间配置器

SGI二级空间配置器的原理是:当区块小于128字节,则以内存池(memory pool)管理,回收时管理一个用户归还的空间,类似于哈希桶。每次配置一块内存,并维护对应的自由链表(free_list)。为了方便管理,SGI二级配置器会对齐到8个字节。(例:需要30字节的空间,自动调整到32字节)。维护16个free_lists,各自管理大小分别为 
8,16,24,32,40,48,56,64,72,80,88,96,104,112,120,128字节。 

3. 什么是智能指针?底层实现?

(1)C++11中引入了智能指针的概念,方便管理堆内存。使用普通指针,容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等,使用智能指针能更好的管理堆内存。

(2)理解智能指针需要从下面三个层次:

从较浅的层面看,智能指针是利用了一种叫做RAII(资源获取即初始化)的技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。

智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。

智能指针还有一个作用是把值语义转换成引用语义。

(3)智能指针#include<memory>,unique_ptr,shared_ptr,weak_ptr(弱引用智能指针)。

(4)unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。相比与原始指针unique_ptr用于其RAII的特性,使得在出现异常的情况下,动态资源能得到释放。unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。

(5)shared_ptr多个指针指向相同的对象。shared_ptr使用引用计数,每一个shared_ptr的拷贝都指向相同的内存。每使用他一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,自动删除所指向的堆内存。shared_ptr内部的引用计数是线程安全的,但是对象的读取需要加锁。

(6)weak_ptr是为了配合shared_ptr而引入的一种智能指针,因为它不具有普通指针的行为,没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。

 

第五篇:操作系统编程

1. 多进程与多线程之间的区别?(最好要了解透彻)

1)进程数据是分开的:共享复杂,需要用IPC,同步简单;多线程共享进程数据:共享简单,同步复杂

2)进程创建销毁、切换复杂,速度慢 ;线程创建销毁、切换简单,速度快 

3)进程占用内存多, CPU利用率低;线程占用内存少, CPU利用率高

4)进程编程简单,调试简单;线程 编程复杂,调试复杂

5)进程间不会相互影响 ;线程一个线程挂掉将导致整个进程挂掉

6)进程适应于多核、多机分布;线程适用于多核

线程所私有的:

线程id、寄存器的值、栈、线程的优先级和调度策略、线程的私有数据、信号屏蔽字、errno变量、

 

2. 什么是进程池和线程池?

在面向对象程序编程中,对象的创建与析构都是一个较为复杂的过程,较费时间,所以为了提高程序的运行效率尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。 
所以我们可以创建一个进程池(线程池),预先放一些进程(线程)进去,要用的时候就直接调用,用完之后再把进程归还给进程池,省下创建删除进程的时间,不过当然就需要额外的开销了。 
利用线程池与进程池可以使管理进程与线程的工作交给系统管理,不需要程序员对里面的线程、进程进行管理。

以进程池为例

进程池是由服务器预先创建的一组子进程,这些子进程的数目在 3~10 个之间(当然这只是典型情况)。线程池中的线程数量应该和CPU数量差不多。

进程池中的所有子进程都运行着相同的代码,并具有相同的属性,比如优先级、 PGID 等。

当有新的任务来到时,主进程将通过某种方式选择进程池中的某一个子进程来为之服务。相比于动态创建子进程,选择一个已经存在的子进程的代价显得小得多。至于主进程选择哪个子进程来为新任务服务,则有两种方法:

主进程使用某种算法来主动选择子进程。最简单、最常用的算法是随机算法和Round Robin(轮流算法)。

主进程和所有子进程通过一个共享的工作队列来同步,子进程都睡眠在该工作队列上。当有新的任务到来时,主进程将任务添加到工作队列中。这将唤醒正在等待任务的子进程,不过只有一个子进程将获得新任务的“接管权”,它可以从工作队列中取出任务并执行之,而其他子进程将继续睡眠在工作队列上。

当选择好子进程后,主进程还需要使用某种通知机制来告诉目标子进程有新任务需要处理,并传递必要的数据。最简单的方式是,在父进程和子进程之间预先建立好一条管道,然后通过管道来实现所有的进程间通信。在父线程和子线程之间传递数据就要简单得多,因为我们可以把这些数据定义为全局,那么它们本身就是被所有线程共享的。

3. 进程间的通信方式有哪些?如何实现的?

信号和信号量是不同的,它们虽然都可以用来同步和互斥,但是信号是使用信号处理器来进行的,信号量是使用P,V操作来实现的。

消息队列是比较高级的一种进程间通信方式,因为它真的是可以在进程间传送message,传送普通字符串也可以。

一个消息队列可以被多个进程所共享(IPC((Inter-Process Communication,进程间通信))就是在这个基础上进行的);如果一个进程消息太多,一个消息队列放不下,也可以用多于一个的消息队列(不管管理可能会比较复杂)。共享消息队列的进程所发送的消息除了message本身外还有一个标志,这个标志可以指明该消息将由哪个进程或者哪类进程接受。每一个共享消息队列的进程针对这个队列也有自己的标志,可以用来申明自己的身份。

共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量,配合使用,来实现进程间的同步和通信。

套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同机器间的进程通信

 

4. 简述inux中的同步与异步机制?

同步:
所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。

例如普通B/S模式(同步):提交请求->等待服务器处理->处理完毕返回 这个期间客户端浏览器不能干任何事

异步:
异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。

例如 ajax请求(异步): 请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕

5.简述阻塞与非阻塞?

阻塞:
阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,cpu不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。

有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回,它还会抢占cpu去执行其他逻辑,也会主动检测io是否准备好。

非阻塞
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

再简单点理解就是:

1. 同步,就是我调用一个功能,该功能没有结束前,我死等结果。
2. 异步,就是我调用一个功能,不需要知道该功能结果,该功能有结果后通知我(回调通知)
3. 阻塞,就是调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
4. 非阻塞,就是调用我(函数),我(函数)立即返回,通过select通知调用者

同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞

阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回

综上可知,同步和异步,阻塞和非阻塞,有些混用,其实它们完全不是一回事,而且它们修饰的对象也不相同。

 

6.简述Linux中的5种I/O模式?

1)阻塞I/O(blocking I/O)
2)非阻塞I/O (nonblocking I/O)
3) I/O复用(select 和poll,还有epoll) (I/O multiplexing)!!!!!(必须搞懂,超究极容易遇到)
4)信号驱动I/O (signal driven I/O (SIGIO))
5)异步I/O (asynchronous I/O (the POSIX aio_functions))

其中前4种都是同步,最后一种才是异步。

详情见:https://www.cnblogs.com/chaser24/p/6112071.html

7. 什么是死锁?四个死锁的条件?避免死锁的方法?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。

产生原因:竞争资源,和进程推进顺序非法

四个条件:

1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2)请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3)不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4)环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

四种解决办法:预防(破坏死锁发四种发生条件中的一个或多个)、避免(银行家算法:如果一个进程增加的资源请求会导致死锁,则不允许此分配,记住当时算的那张矩阵图)、检测与解除

8. Linux的任务调度机制是什么?

Linux 分实时进程和普通进程,实时进程应该先于普通进程而运行。实时进程:

1) FIFO(先来先服务调度)

2) RR(时间片轮转调度)。

每个进程有两个优先级(动态优先级和实时优先级),实时优先级就是用来衡量实时进程是否值得运行的。 非实时进程有两种优先级,一种是静态优先级,另一种是动态优先级。实时进程又增加了第三种优先级,实时优先级。优先级越高,得到CPU时间的机会也就越大。

9.标准库函数与系统调用的区别?

系统调用:是操作系统为用户态运行的进程和硬件设备(如CPU、磁盘、打印机等)进行交互提供的一组接口,即就是设置在应用程序和硬件设备之间的一个接口层。inux内核是单内核,结构紧凑,执行速度快,各个模块之间是直接调用的关系。linux系统上到下依次是用户进程->linux内核->硬件。其中系统调用接口是位于Linux内核中的,整个linux系统从上到下可以是:用户进程->系统调用接口->linux内核子系统->硬件,也就是说Linux内核包括了系统调用接口和内核子系统两部分;或者从下到上可以是:物理硬件->OS内核->OS服务->应用程序,操作系统起到“承上启下”作用,向下管理物理硬件,向上为操作系服务和应用程序提供接口,这里的接口就是系统调用了。
库函数:把函数放到库里。是把一些常用到的函数编完放到一个lib文件里,供别人用。别人用的时候把它所在的文件名用#include<>加到里面就可以了。一类是c语言标准规定的库函数,一类是编译器特定的库函数。
系统调用是为了方便使用操作系统的接口,而库函数则是为了人们编程的方便。

 

第六篇:网络编程

1. 分别简述三次握手与四次挥手的过程?

三次握手:C----->SYN K

              S------>ACK K+1 SYN J

              C------->ACK J+1   

              DONE!

client 的 connect  引起3次握手

server 在socket, bind, listen后,阻塞在accept,三次握手完成后,accept返回一个fd,

 

 

2. tcp和udp之间的区别?

1)基于连接与无连接

2)对系统资源的要求(TCP较多,UDP少)

3)UDP程序结构较简单

4)流模式与数据报模式

5)TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证

6)TCP有拥塞控制和流量控制,UDP没有

TCP提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。

是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

3. select、poll、epoll之间的区别?

https://www.cnblogs.com/Anker/p/3265058.html(参考阅读)

 

4. epoll有哪些触发模式?

(必须非常详尽的解释水平触发和边缘触发的区别,以及边缘触发在编程中要做哪些更多的确认)

注意:epoll必须深入理解,必须要张口就来,必须随心所欲说出来。

epoll有EPOLLLT和EPOLLET两种触发模式,LT是默认的模式,ET是“高速”模式。LT模式下,只要这个fd还有数据可读,每次 epoll_wait都会返回它的事件,提醒用户程序去操作,而在ET(边缘触发)模式中,它只会提示一次,直到下次再有数据流入之前都不会再提示了,无论fd中是否还有数据可读。所以在ET模式下,read一个fd的时候一定要把它的buffer读光,也就是说一直读到read的返回值小于请求值。

也就是说在LT模式的情况下一定要确认收发的数据包的buffer是不是足够大如果收发数据包大小大于buffer的大小的时候就可能会出现数据丢失的情况。

 

5. 若是有大规模的数据连接,并发模型如何设计?

Epoll+线程池(epoll可以采用libevent处理)

发布了15 篇原创文章 · 获赞 19 · 访问量 6601

Guess you like

Origin blog.csdn.net/wsq_zqfl/article/details/104429090