以下题目结合CentOS系统特性(如进程/线程管理、内存布局、网络编程)与C++核心知识点,覆盖面试高频考点及实用场景。
答案:
在CentOS中,可通过Valgrind工具检测C++程序的内存泄漏。常用命令如下:
valgrind --leak-check=full ./your_program
--leak-check=full:显示详细的泄漏信息(包括泄漏位置、内存地址、调用栈)。definitely lost表示确认的内存泄漏(未释放的堆内存),indirectly lost表示间接泄漏(如结构体成员未释放)。LD_LIBRARY_PATH指定库路径,例如:valgrind --leak-check=full LD_LIBRARY_PATH=/usr/local/lib ./your_program
fork()与C++多进程编程:如何避免僵尸进程?答案:
fork()创建的子进程结束后,若父进程未调用wait()或waitpid()回收其退出状态,子进程会变成僵尸进程(占用进程ID但无资源)。
解决方法:
wait(NULL)阻塞等待子进程结束:#include <sys/wait.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if (pid == 0) { // 子进程
printf("Child process\n");
exit(0);
} else if (pid > 0) { // 父进程
wait(NULL); // 等待子进程结束
printf("Child exited\n");
}
return 0;
}
SIGCHLD信号(子进程退出时发送),内核会自动回收僵尸进程:signal(SIGCHLD, SIG_IGN);
ps aux | grep 'Z'查看,若长期存在需重启服务或修复代码。pthread_mutex_t与std::mutex的区别答案:
pthread_mutex_t:POSIX线程库提供的互斥锁,需手动初始化(pthread_mutex_init)与销毁(pthread_mutex_destroy),适用于C++11前的多线程编程。#include <pthread.h>
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL); // 初始化
pthread_mutex_lock(&mutex); // 加锁
// 临界区代码
pthread_mutex_unlock(&mutex); // 解锁
pthread_mutex_destroy(&mutex); // 销毁
std::mutex:C++11标准库提供的互斥锁,无需手动管理生命周期,支持RAII(如std::lock_guard自动加锁/解锁),更安全。#include <mutex>
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx); // 自动加锁
// 临界区代码
} // 自动解锁
std::mutex是C++标准,跨平台性更好,推荐优先使用。答案:
hello.cpp编译为libhello.so:g++ -shared -fPIC hello.cpp -o libhello.so
-shared:生成动态库;-fPIC:生成位置无关代码(动态库加载时无需固定地址)。main.cpp调用动态库中的函数,编译时指定库路径:g++ main.cpp -L. -lhello -o main
-L.:指定库路径为当前目录;-lhello:链接libhello.so(省略lib前缀与.so后缀)。LD_LIBRARY_PATH环境变量:export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main
/usr/lib或/usr/local/lib,无需修改LD_LIBRARY_PATH。答案:
使用signal()或sigaction()函数捕获信号,例如捕获SIGSEGV(段错误)并打印堆栈:
#include <signal.h>
#include <execinfo.h>
#include <iostream>
#include <unistd.h>
void signal_handler(int sig) {
void* array[10];
size_t size = backtrace(array, 10); // 获取堆栈信息
std::cerr << "Error: signal " << sig << std::endl;
backtrace_symbols_fd(array, size, STDERR_FILENO); // 打印堆栈到标准错误
exit(1);
}
int main() {
signal(SIGSEGV, signal_handler); // 注册信号处理函数
int* p = nullptr;
*p = 10; // 触发段错误
return 0;
}
backtrace()获取堆栈帧地址,backtrace_symbols_fd()将地址转换为可读的函数名与行号(需编译时加-rdynamic选项)。gdb进一步分析core dump文件(需开启ulimit -c unlimited)。open()与fopen()的区别答案:
open():POSIX系统调用,返回文件描述符(整数),支持底层操作(如read()、write()),适用于高性能场景。#include <fcntl.h>
#include <unistd.h>
int fd = open("test.txt", O_WRONLY | O_CREAT, 0644); // 打开/创建文件
write(fd, "Hello, CentOS!", 14); // 写入数据
close(fd); // 关闭文件
fopen():C标准库函数,返回FILE*指针,支持缓冲IO(如fprintf()、fscanf()),适用于常规文件操作。#include <cstdio>
FILE* fp = fopen("test.txt", "w"); // 打开文件
fprintf(fp, "Hello, CentOS!"); // 写入数据
fclose(fp); // 关闭文件
open()更底层,性能更高,但需手动处理缓冲;fopen()更易用,适合大多数场景。答案:
CentOS下C++常用的IPC方法包括:
pipe())和命名管道(mkfifo())。int fd[2];
pipe(fd); // 创建匿名管道
if (fork() == 0) { // 子进程
close(fd[0]); // 关闭读端
write(fd[1], "Hello", 6);
} else { // 父进程
close(fd[1]); // 关闭写端
char buf[10];
read(fd[0], buf, 10);
std::cout << "Received: " << buf << std::endl;
}
semaphore)。#include <sys/ipc.h>
#include <sys/shm.h>
int shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | 0666); // 创建共享内存
char* shm = (char*)shmat(shmid, NULL, 0); // 映射到进程地址空间
strcpy(shm, "Hello from Process 1!");
shmdt(shm); // 解除映射
shmctl(shmid, IPC_RMID, NULL); // 删除共享内存
msgget()创建队列,msgsnd()发送消息,msgrcv()接收消息。semget()创建信号量,semop()操作信号量(如P/V操作)。gprof?答案:
gprof是GNU性能分析工具,用于统计函数调用次数与耗时,步骤如下:
-pg选项:生成带分析信息的可执行文件。g++ -pg your_program.cpp -o your_program
gmon.out文件(包含性能数据)。./your_program
gprof生成报告。gprof your_program gmon.out > analysis.txt
%time、self time)。gprof仅支持单线程程序,多线程程序需使用perf工具(perf record、perf report)。