2023 C/C++ Software Development Engineer School Recruitment Interview Frequently Asked Knowledge Points Review Part 8

Table of contents

52. How is vector stored?

  • stringThe address of the object stored in the underlying array of vector
  • Because random access needs to be guaranteed, but the string itself cannot determine its size immediately, so the string object cannot be stored directly, but the address is stored

53. The underlying principle of epoll

53.1 Comparing select and poll

The way epoll works is very efficient

  1. select and poll use a linear method to detect whether the socket collection needs to be processed, while epoll manages the collection to be detected based on the red-black tree
  2. select and poll need to linearly scan the entire collection every time, but epoll is a callback method, which can directly know which collections need to respond
  3. select and poll need to judge the returned set to know which file descriptors are ready, and epoll can directly get the ready file descriptor set
  4. epoll has no limit on the maximum file descriptor, only limited by the limit of the file descriptor that the system can open

three operation functions

  1. create
  2. Add and maintain management
  3. Check if there is a ready file descriptor
#include <sys/epoll.h>
// 创建epoll实例,通过一棵红黑树管理待检测集合
int epoll_create(int size);
// 管理红黑树上的文件描述符(添加、修改、删除)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
// 检测epoll树中是否有就绪的文件描述符
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

forint epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

// 联合体, 多个变量共用同一块内存        
typedef union epoll_data {
    
    
 	void        *ptr;
	int          fd;	// 通常情况下使用这个成员, 和epoll_ctl的第三个参数相同即可
	uint32_t     u32;
	uint64_t     u64;
} epoll_data_t;

struct epoll_event {
    
    
	uint32_t     events;      /* Epoll events */
	epoll_data_t data;        /* User data variable */
};
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

// epfd  就是创建的epfd实体
// op    用于指定执行什么管理操作,是删除、添加、还是修改
// fd    用于指定要添加的socket是啥
// event 是一个结构体,用来指定fd相关事件以及一些用户数据,事件的话有EPOLLIN:读事件、EPOLLOUT:写事件、EPOLLERR:异常事件

forint epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

// epfd    是epoll对象实例
// events  是返回的就绪状态的文件描述符
// maxevents 表示 结构体的容量
// 0-> 不等待  -1-> 一直等待  
53.2 Working modes of ET and LT

LT refers to horizontal triggering : This is the default way of working. If the file descriptor needs to be responded to, the corresponding event will be triggered. If we do not process it, or if it is not processed completely, it will continue to trigger

ET refers to edge triggering : this is a relatively high-level way, if the file descriptor needs to be responded to, the corresponding event will only be triggered once, regardless of whether we process it or not

  • Receive data in a loop, hoping to process it all at once
  • Therefore, it is necessary to use non-blocking functions to send and receive data, especially to accept

54. Understanding of processes, threads, and coroutines and their communication methods

Understanding of processes, threads, coroutines and their communication methods

54.1 Meaning of processes
  • A process is the basic unit for resource allocation by the operating system ; it can apply for and own system resources, which is a dynamic concept ;
  • A process has its own address space , that is, it has its own independent memory space . Different processes need IPC, that is, inter-process communication ( pipelines, signals, message queues, shared memory, semaphores, and sockets );
  • Since each process has its own system resources, the overhead of context switching ( stacks, registers, virtual memory, file handles, etc. ) is relatively large; process switching is completed by the operating system.
54.2 Meaning of threads
  • A thread is an execution entity of a process and the basic unit of CPU scheduling; the thread itself basically does not own system resources, but only some resources (PC, registers, stack) that are essential in operation
  • Threads belonging to the same process share all resources owned by the process ; the communication between threads mainly depends on shared memory, global variables, etc.
  • Compared with process thread switching, it only needs to save and restore PC, registers, and stack , so the overhead is small; thread switching is completed by the operating system.
54.3 The meaning of coroutines
  • The coroutine is a lightweight thread in user mode , and the scheduling of the coroutine is completely controlled by the user without entering the kernel mode;
  • Coroutines have fewer resources and have their own registers and stacks . Coroutine switching only needs to protect these resources. The context switching overhead of coroutines is the smallest and the fastest ;
  • The coroutine can access global variables without locking ( because the scheduling of the coroutine is controlled by the user, there will be no read-write competition, so it can be unlocked -my own understanding)
54.4 Interprocess Communication IPC

https://www.cnblogs.com/zhuminghui/p/15405591.html

  1. Communication between processes goes through the kernel

  2. Commonly used IPC methods are: pipeline, message queue, shared memory, semaphore, signal, socket, etc.

  • Why is communication needed?

    • Because the address spaces between different processes are independent, if cooperation is required, a special way of communication is required, that is, IPC communication

54.4.1, pipeline (pipe)

Anonymous pipes are half-duplex, one-way, if you need to communicate with each other, you need to create two pipes, and can only be used between processes that are related by affinity. Affinity is like a parent-child process.

Well-known pipes are also half-duplex and unidirectional, but allow communication between unrelated processes .

缺点:The pipeline communication method is inefficient and not suitable for frequent data exchange between processes.

54.4.2, message queue

The message queue is a linked list of messages stored in the kernel , so the life cycle of the message queue follows the kernel and the operating system.

The message body is a user-defined data type . The sender and receiver of the message must agree on the data type of the message body. Therefore, each message body is a storage block with a fixed format and size.

  • Communication between two processes is like sending an email, you send an email, and I reply

  • 优点:It solves the shortcomings of less signal transmission information, pipelines can only be used in unformatted byte streams, and limited buffer size;

  • 缺点:The communication is not timely, the size of the message body is limited, and the frequent copy process between the user state and the kernel state will occur

54.4.3, shared memory

Shared memory is a piece of memory that both processes can access, so if one process writes data, the other process sees it immediately. Therefore, the efficiency is very high, and it is also the fastest of all IPCs .

54.4.4, Signal volume

Semaphores are mainly used to cooperate with shared memory to ensure mutual exclusion and synchronization of shared resources, and to prevent data access conflicts and overwriting problems

54.4.5. Signals

LinuxDozens of signals are defined internally, representing different meanings. A signal can be sent to a process at any time to tell a process that an event has occurred .

  • Signal sources are mainly 硬件来源and软件来源

  • When a process receives a signal, there are generally three processing methods

    1. Execute the default action provided by Linux for each signal
    2. Capture the signal and execute our own defined processing function
    3. ignore

54.4.6、Socket

It can be used for communication between different processes on different devices.

54.5 Communication between threads

The main purpose of thread communication is thread synchronization , so there is no communication mechanism for exchanging data like in a process

Mainly lock mechanism, such as mutex, read-write lock, condition variable, semaphore

55. Usage of define macro definition

The usage of define macro definition

  1. Prevent a header file from being double-included
    #ifndef HEAD_H
    #define HEAD_H
    // 头文件内容
    
    #endif
    
  2. Find the maximum and minimum of two numbers

    The essence is to use one sentence, one line of code, and one expression to realize the function of the macro, and the result of the expression is the target of the macro

    #define MAX(x, y) ((x) > (y) ? (x) : (y))
    #define MIN(x, y) ((x) > (y) ? (y) : (x))
    // 宏函数的调用
    cout << MAX(10, 100) << endl; // 100
    
  3. Returns the number of array elements
    #define ARR_SIZE(arr) (sizeof((arr)) / sizeof((arr[0])))
    
    // 调用
    int arr[15] = {
          
          0};
    cout << ARR_SIZE(arr) << endl; // 15
    
  4. get the address of a variable
    #define GET_PTR(var) ((void *)&(var))
    
    // 调用
    double d = 100.11;
    cout << GET_PTR(d) << endl; // 0x72fdc8
    
  5. Get a byte or int from the specified address
    #define MEM_B(ptr) (*((char *)(ptr)))  // 获取一个字节
    #define MEM_INT(ptr) (*((int *)(ptr))) // 从一块地址上去一个int
    
  6. Convert a letter to uppercase
    #define UPCASE(c) (((c) <= ('z') && (c) >= ('a')) ? ((char)((c) - ('a') + ('A'))) : (c))
    
    cout << UPCASE('a') << endl; // A
    cout << UPCASE('A') << endl; // A
    

56. Details about arrays, pointers, and array names

  1. The array name itself has an array attribute, and the array size can be directly calculated for the array name sizeof; this attribute does not exist after assignment
    // 数组名本身有数组属性
    int arr[15] = {
          
          0};
    cout << size(arr) << endl; // 60
    
    // 如果将数组名传递到函数中就不带有数组属性了,将退化为一个指针
    cout << func1(arr) << endl;  // 如果调用下面的函数,就会丧失数组属性
    
    int func1(int arrp[])
    {
          
          
        return sizeof(arrp);  // 退化为指针后,sizeof得到的仅仅是指针大小
    }
    
  2. The size of the 32-bit machine pointer is 4 bytes, and the size of the 64-bit machine pointer is 8 bytes
  3. The usage of the array name is more similar to one 指针常量, that is, the pointing of the pointer cannot be changed, pointing to the first address of the array
    int arr[10] = {
          
          0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    arr++;  // 不合法---->因为数组名arr是一个指针常量,自身是不可以改变的
    int a =  *(arr + 1);    // 等价于arr[1];
    
    int* ptr = arr; 		//通过赋值操作,用一个普通的指针指向了数组arr的首地址
    ptr++;	// 合法
    ++ptr;	// 合法
    
    int* ptr2 = &arr[0];  	// 等价于 int* ptr = arr; 结果都是使得一个普通指针指向了数组的首地址
    
  4. The first address of the array is equivalent to the starting address of the first element of the array
    int arr[3] = {
          
          1, 2, 3};
    // arr指向数组的首地址
    // &arr[0]指向数组第一个元素的起始地址
    // 两者是同一个位置
    
  5. pointer movement and operation
    • Pointers and pointers can only perform subtraction operations ( how many elements are separated ), and cannot perform operations such as multiplication, division, and addition

    • A pointer can only add a constant

      int arr[10] = {
              
              0};
      int * p = arr;
      *(p + 9) 指向最后一个元素 等价于 arr[9]
      同样也等价于*(arr + 9)
          
      在编译器中,arr[i]的访问过程就是转化为 *(arr + i)然后访问的
      
  6. Regarding arrays of pointers and数组指针
    // 声明一个指针数组,该数组有10个元素,其中每个元素都是一个指向 int 类型对象的指针
    int *arr[10];
    // 声明一个数组指针,该指针指向一个 int 类型的一维数组
    int (*arr)[10];  
    

57. The specific process of compilation

The specific process of compilation

  1. The compilation process can be divided into 4 steps 预处理———编译汇编链接
  2. preprocessing
    • Expand header files, expand macro definitions, delete comments
    • gcc commandgcc -E ...
    • The generated intermediate file .i文件is still the source code
  3. compile
    • Compile .ifiles into .sfiles; that is, convert source code files into assembly code
    • gcc commandgcc -S ...
    • The generated intermediate file .s文件is assembly code
    • It is at this stage that the main compilation optimizations take place
  4. compilation
    • Translate .sa file line by line into .oa file; that is, from assembly to binary machine code
    • gcc commandgcc -c ...
    • The generated intermediate file is.o文件
  5. Link
    • At this stage, GCC calls the linker to link the libraries that the program needs to call and multiple.o files to generate executable binary files
    • gcc command: gcc + 源文件Compile directly, no other parameters are required
    • Generated by default a.out文件, can also be used to -o 文件名customize the name of the generated file (this command can also be used in the above stages)

Guess you like

Origin blog.csdn.net/qq_40459977/article/details/127519327
Recommended