微信搜索“编程笔记本”,获取更多信息
------------- codingbook2020 -------------
今天继续分享 CVTE 视源股份的 C++ 软件开发的二面面试题,题目依旧很多,哈撒给!
面试题
文章目录
-
-
- 面试题
- 2.1 TCP 怎么保证可靠传输?
- 2.2 TCP 的停止等待协议是什么?
- 2.3 线程同步的方式?
- 2.4 线程之间怎么传递信号?
- 2.5 C++ 怎么传递信号?
- 2.6 什么是内存泄漏?
- 2.7 如果我 new 了一块内存,然后在 delete 之前这个进程被系统杀死了。这样算内存泄漏吗?
- 2.8 Linux 755 指的是什么权限?
- 2.9 wine 使 windows 程序能够在 Linux 下使用,你觉得它是怎么实现的?
- 2.10 系统调用和函数调用的区别是什么?
- 2.11 dll 是什么文件?什么情况下会发生 dll 缺失?
- 2.12 静态库和动态库的区别是什么?
- 2.13 怎么解决内存泄漏问题?你觉得哪些定位内存泄漏的开源工具是怎么实现的?
- 2.14 C++ 下的可执行文件和 Linux 下的可执行文件分别是什么后缀名?
- 2.15 windows 下 C++ 文件有哪些后缀,分别是什么用途?
- 2.16 如果在调试过程中,出现了需要循环很多次才出现的错误应该怎么调试?
- 2.17 最近在编程上遇到什么问题?
- 2.18 写出单例模式线程安全的代码?若多个线程同时判断到当前对象未创建,应该怎么解决?C++11 中可以用什么特性替换单例模式中的 static 写法?
- 2.19 git 和 svn 的区别是什么?
- 2.20 讲一下 STL 中的 map ?map 和 unordered map 的区别是什么?
-
2.1 TCP 怎么保证可靠传输?
TCP 通过序列号、检验和、确认应答信号、重发控制、连接管理、窗口控制、流量控制、拥塞控制实现可靠性。
关于这些机制的具体描述参见往期笔记:TCP/IP 协议栈。
2.2 TCP 的停止等待协议是什么?
停止等待协议是最简单但也是最基础的数据链路层协议。具体来说就是,每发送完一个分组就停止发送,等待对方的确认,在收到确认消息后再发送下一个分组。
2.3 线程同步的方式?
线程同步:即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,其他线程处于等待状态。
同步方式
常见的线程同步主要有如下几种方式:
- 临界区
临界区的作用:线程在执行代码时将代码锁定,不允许其他线程执行,只有该线程离开后,其他线程才能使用这些代码。常用的操作有:初始化临界区、临界区加锁、临界区解锁、释放临界区。 - 信号量
一个线程完成了某一个动作就通过信号量告诉别的线程,别的线程再进行某些动作。 - 事件
事件对象也可以通过通知操作的方式来保持线程的同步。常用的操作有:创建一个事件对象、打开一个事件、设置事件、复位事件、等待一个事件、等待多个事件。使用临界区只能同步同一进程中的线程,而使用事件内核对象则可以对进程外的线程进行同步,其前提是得到对此事件对象的访问权。 - 互斥量
一个线程占用了某一个资源,就对该资源加锁,别的线程无法访问,直到这个线程解锁,其他的线程才开始可以利用这个资源。
有关线程及线程间同步的更多介绍参见往期笔记:操作系统基础知识:程序、进程与线程。
2.4 线程之间怎么传递信号?
线程的信号量与进程的信号量类似,但是使用线程的信号量可以高效地完成基于线程地资源计数。信号量实际上是一个非负的整数计数器,用来实现对公共资源的控制。在公共资源增加的时候,信号量的值增加;公共资源消耗的时候信号量减少;只有当信号量的值大于 0 时,才能访问信号量代表的公共资源。
常用的操作有:
- 线程信号量初始化函数
sem_init()
- 线程信号量增加函数
sem_post()
- 线程信号量等待函数
sem_wait()
- 线程信号量销毁函数
sem_destroy()
下面我们来看一个线程间使用信号量的例子:使用一个全局变量来计数,一个线程通过增加信号量来模拟生产者,另一个线程通过获取信号量类模拟消费者。
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
// 定义信号量
sem_t sem;
int running = 1;
// 生产者线程函数
void producer () {
int semVal = 0;
while (running) {
usleep(100000);
// 信号量增加并获取信号量的值
sem_post(&sem);
sem_getvalue(&sem, &semVal);
printf("生产一个,剩余总数:%d\n", semVal);
}
}
// 消费者线程函数
void consumer() {
int semVal = 0;
while (running) {
usleep(100000);
// 等待信号量并获取信号量的值
sem_wait(&sem);
sem_getvalue(&sem, &semVal);
printf("消费一个,剩余总数:%d\n", semVal);
}
}
int main()
{
pthread_t producer_t, consumer_t;
// 信号量只在统一进程的多个线程间共享,并且信号量的初值为16
sem_init(&sem, 0, 16);
// 创建线程
pthread_create(&producer_t, NULL, (void*)producer, NULL);
pthread_create(&consumer_t, NULL, (void*)consumer, NULL);
// 运行时间
sleep(1);
// 设置线程退出
running = 0;
// 等待线程退出
pthread_join(producer_t, NULL);
pthread_join(consumer_t, NULL);
// 销毁信号量
sem_destroy(&sem);
return 0;
}
/*
运行结果:
jincheng@jincheng-PC:~/Desktop$ gcc -lpthread -o test test.c
jincheng@jincheng-PC:~/Desktop$ ./test
消费一个,剩余总数:15
生产一个,剩余总数:1