面试题答案
一键面试架构设计
- 节点通信:使用Socket进行节点间的网络通信。每个节点创建一个Socket监听特定端口,用于接收其他节点发送的消息。同时,可创建另一个Socket用于主动向其他节点发送消息。
- 数据结构:在每个节点上定义一个共享的数据结构,用于存储任务执行状态等信息。例如:
typedef struct {
int taskB_done;
int taskC_done;
pthread_mutex_t mutex;
pthread_cond_t cond;
} NodeStatus;
- 线程模型:每个节点的C语言程序可采用多线程模型。主线程负责监听网络消息,接收到其他节点完成任务的消息后,更新共享数据结构。其他线程负责执行本地任务,当需要等待其他节点任务完成时,通过条件变量等待。
数据传输方式
- 消息格式:定义一种简单的消息格式,例如包含消息类型(表示是任务完成通知等)、发送节点ID等信息。例如:
typedef struct {
int type;
int sender_id;
// 其他可能的字段
} Message;
- Socket发送与接收:使用
send
和recv
函数进行消息的发送和接收。例如,节点B完成任务后,构造消息并发送给节点A:
Message msg;
msg.type = TASK_DONE;
msg.sender_id = NODE_B_ID;
send(sockfd, &msg, sizeof(Message), 0);
节点A监听Socket接收消息:
recv(sockfd, &msg, sizeof(Message), 0);
if (msg.type == TASK_DONE) {
// 更新共享数据结构
}
条件变量的具体使用方法
- 初始化:在每个节点的共享数据结构初始化时,初始化互斥锁和条件变量:
NodeStatus status;
status.taskB_done = 0;
status.taskC_done = 0;
pthread_mutex_init(&status.mutex, NULL);
pthread_cond_init(&status.cond, NULL);
- 等待条件:在节点A中,当需要等待节点B和C完成任务时,使用如下代码:
pthread_mutex_lock(&status.mutex);
while (!(status.taskB_done && status.taskC_done)) {
pthread_cond_wait(&status.cond, &status.mutex);
}
// 继续执行下一步操作
pthread_mutex_unlock(&status.mutex);
- 通知条件:在节点B和C完成任务后,更新共享数据结构并通知节点A:
pthread_mutex_lock(&status.mutex);
if (node_id == NODE_B_ID) {
status.taskB_done = 1;
} else if (node_id == NODE_C_ID) {
status.taskC_done = 1;
}
pthread_cond_broadcast(&status.cond);
pthread_mutex_unlock(&status.mutex);
可能出现的问题及应对策略
- 网络延迟或故障:
- 问题:节点间消息传输可能出现延迟或丢失,导致等待节点长时间等待。
- 策略:引入超时机制,在
pthread_cond_wait
设置超时时间。同时,采用重传机制,发送方在一定时间内未收到确认消息时,重发任务完成通知。
- 死锁:
- 问题:如果互斥锁使用不当,可能导致死锁,例如在持有锁的情况下调用可能阻塞的函数。
- 策略:确保锁的获取和释放顺序正确,避免嵌套锁等可能导致死锁的情况。在调试时,使用工具如
valgrind
检测死锁。
- 竞争条件:
- 问题:多个线程同时访问和修改共享数据结构可能导致竞争条件。
- 策略:通过互斥锁保证同一时间只有一个线程能访问和修改共享数据结构。并且在条件变量等待和通知时,始终在持有互斥锁的情况下进行操作。