面试题答案
一键面试整体设计思路
- 跨平台创建进程:在 Windows 平台使用
CreateProcess
函数,在 Linux 平台使用fork
和exec
系列函数。 - 数据交互:可以使用管道(Pipe)进行进程间通信。在 Windows 上使用
CreatePipe
创建管道,在 Linux 上使用pipe
函数。 - 同步机制:使用互斥锁(Mutex)或信号量(Semaphore)来保证数据一致性和完整性。在 Windows 上可以使用
CreateMutex
和WaitForSingleObject
等函数,在 Linux 上可以使用pthread_mutex_t
和pthread_mutex_lock
等函数。
涉及到的跨平台 API 及函数
- Windows
- 创建进程:
CreateProcess
- 创建管道:
CreatePipe
- 互斥锁:
CreateMutex
,WaitForSingleObject
,ReleaseMutex
- 创建进程:
- Linux
- 创建进程:
fork
,exec
系列(如execlp
) - 创建管道:
pipe
- 互斥锁:
pthread_mutex_t
,pthread_mutex_init
,pthread_mutex_lock
,pthread_mutex_unlock
,pthread_mutex_destroy
- 创建进程:
代码实现
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h> // Linux 系统调用头文件
#include <windows.h> // Windows API 头文件
#include <pthread.h> // Linux 线程相关头文件
#ifdef _WIN32
#define BUFFER_SIZE 1024
// Windows 平台代码
void windowsCreateProcess() {
HANDLE hReadPipe, hWritePipe;
SECURITY_ATTRIBUTES saAttr;
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
if (!CreatePipe(&hReadPipe, &hWritePipe, &saAttr, 0)) {
std::cerr << "CreatePipe failed." << std::endl;
return;
}
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.hStdError = hWritePipe;
si.hStdOutput = hWritePipe;
si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcess(NULL, "child_process.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
std::cerr << "CreateProcess failed." << std::endl;
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
return;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
char buffer[BUFFER_SIZE];
DWORD bytesRead;
if (!ReadFile(hReadPipe, buffer, BUFFER_SIZE - 1, &bytesRead, NULL)) {
std::cerr << "ReadFile failed." << std::endl;
}
buffer[bytesRead] = '\0';
std::cout << "Child process output: " << buffer << std::endl;
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
}
#endif
#ifdef __linux__
// Linux 平台代码
void linuxCreateProcess() {
int pipefd[2];
if (pipe(pipefd) == -1) {
std::cerr << "pipe failed." << std::endl;
return;
}
pid_t pid = fork();
if (pid == -1) {
std::cerr << "fork failed." << std::endl;
close(pipefd[0]);
close(pipefd[1]);
return;
} else if (pid == 0) {
// 子进程
close(pipefd[0]);
if (dup2(pipefd[1], STDOUT_FILENO) == -1) {
std::cerr << "dup2 failed." << std::endl;
}
if (execlp("./child_process", "./child_process", NULL) == -1) {
std::cerr << "execlp failed." << std::endl;
}
} else {
// 父进程
close(pipefd[1]);
char buffer[BUFFER_SIZE];
ssize_t bytesRead = read(pipefd[0], buffer, BUFFER_SIZE - 1);
if (bytesRead == -1) {
std::cerr << "read failed." << std::endl;
}
buffer[bytesRead] = '\0';
std::cout << "Child process output: " << buffer << std::endl;
close(pipefd[0]);
}
}
#endif
int main() {
#ifdef _WIN32
windowsCreateProcess();
#elif __linux__
linuxCreateProcess();
#endif
return 0;
}
假设 child_process
是一个简单的可执行文件,它输出一些信息。在实际应用中,可以根据需求修改子进程的功能和数据交互方式。
可能出现的性能瓶颈及优化策略
- 性能瓶颈
- 管道通信:如果频繁进行大量数据的读写,管道可能成为性能瓶颈。管道是一种同步通信机制,读写操作可能会阻塞,导致进程等待。
- 同步机制:过度使用互斥锁或信号量可能导致线程或进程频繁等待,降低系统并发性能。
- 优化策略
- 管道通信:可以采用异步 I/O 操作来减少阻塞时间。在 Windows 上可以使用
ReadFileEx
和WriteFileEx
等异步函数,在 Linux 上可以使用aio_read
和aio_write
等异步 I/O 函数。 - 同步机制:尽量减少锁的粒度和持有时间。例如,将大的临界区分解为多个小的临界区,只在真正需要保护数据的地方使用锁。同时,可以考虑使用读写锁(如
pthread_rwlock_t
在 Linux 上),对于读多写少的场景,可以提高并发性能。
- 管道通信:可以采用异步 I/O 操作来减少阻塞时间。在 Windows 上可以使用