面试题答案
一键面试使用联合体在多线程状态机场景下的挑战
- 数据竞争:由于联合体的所有成员共享同一块内存空间,不同线程同时访问和修改联合体成员时,可能导致数据竞争。例如,一个线程正在修改联合体中某个成员的值,而另一个线程同时读取该联合体,可能读到不一致的数据。
- 同步问题:当不同线程触发状态转移时,可能同时修改状态机的状态(存储在联合体中),导致状态不一致。此外,对于依赖于状态的操作,也需要确保在状态更新期间其他线程不会进行干扰。
解决方法
- 互斥锁(Mutex):使用互斥锁来保护对联合体的访问。在访问联合体成员之前,先获取互斥锁,访问完成后释放互斥锁,这样可以保证同一时间只有一个线程能够访问联合体。
- 条件变量(Condition Variable):用于线程间的同步。当状态发生变化满足某些条件时,通过条件变量通知等待的线程,以确保线程在合适的时机进行操作。
核心代码示例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
// 定义联合体表示状态机的状态
union State {
int numeric_state;
char text_state[10];
};
// 定义状态机结构体
typedef struct {
union State current_state;
pthread_mutex_t mutex;
pthread_cond_t cond;
} StateMachine;
// 初始化状态机
void init_state_machine(StateMachine *sm) {
sm->current_state.numeric_state = 0;
pthread_mutex_init(&sm->mutex, NULL);
pthread_cond_init(&sm->cond, NULL);
}
// 释放状态机资源
void destroy_state_machine(StateMachine *sm) {
pthread_mutex_destroy(&sm->mutex);
pthread_cond_destroy(&sm->cond);
}
// 状态转移函数
void transition_state(StateMachine *sm, int new_state) {
pthread_mutex_lock(&sm->mutex);
sm->current_state.numeric_state = new_state;
// 状态转移后可以通过条件变量通知其他线程
pthread_cond_broadcast(&sm->cond);
pthread_mutex_unlock(&sm->mutex);
}
// 线程函数,模拟对状态机的操作
void* thread_function(void* arg) {
StateMachine *sm = (StateMachine *)arg;
pthread_mutex_lock(&sm->mutex);
// 等待状态满足某个条件
while (sm->current_state.numeric_state != 5) {
pthread_cond_wait(&sm->cond, &sm->mutex);
}
printf("Thread: State is now 5, performing action.\n");
pthread_mutex_unlock(&sm->mutex);
return NULL;
}
int main() {
StateMachine sm;
init_state_machine(&sm);
pthread_t thread;
pthread_create(&thread, NULL, thread_function, &sm);
// 主线程模拟状态转移
for (int i = 0; i < 10; i++) {
sleep(1);
transition_state(&sm, i);
if (i == 5) {
printf("Main: State set to 5, should trigger thread action.\n");
}
}
pthread_join(thread, NULL);
destroy_state_machine(&sm);
return 0;
}
代码注释
- 联合体定义:
union State {
int numeric_state;
char text_state[10];
};
定义了一个联合体 State
,它可以存储一个整数类型的状态或者一个字符串类型的状态,成员共享同一块内存空间。
- 状态机结构体定义:
typedef struct {
union State current_state;
pthread_mutex_t mutex;
pthread_cond_t cond;
} StateMachine;
定义了状态机结构体 StateMachine
,包含联合体类型的当前状态 current_state
,以及用于同步的互斥锁 mutex
和条件变量 cond
。
- 初始化状态机函数:
void init_state_machine(StateMachine *sm) {
sm->current_state.numeric_state = 0;
pthread_mutex_init(&sm->mutex, NULL);
pthread_cond_init(&sm->cond, NULL);
}
初始化状态机的当前状态为0,并初始化互斥锁和条件变量。
- 释放状态机资源函数:
void destroy_state_machine(StateMachine *sm) {
pthread_mutex_destroy(&sm->mutex);
pthread_cond_destroy(&sm->cond);
}
销毁互斥锁和条件变量,释放资源。
- 状态转移函数:
void transition_state(StateMachine *sm, int new_state) {
pthread_mutex_lock(&sm->mutex);
sm->current_state.numeric_state = new_state;
// 状态转移后可以通过条件变量通知其他线程
pthread_cond_broadcast(&sm->cond);
pthread_mutex_unlock(&sm->mutex);
}
获取互斥锁,更新状态机的当前状态,然后通过条件变量通知所有等待的线程,最后释放互斥锁。
- 线程函数:
void* thread_function(void* arg) {
StateMachine *sm = (StateMachine *)arg;
pthread_mutex_lock(&sm->mutex);
// 等待状态满足某个条件
while (sm->current_state.numeric_state != 5) {
pthread_cond_wait(&sm->cond, &sm->mutex);
}
printf("Thread: State is now 5, performing action.\n");
pthread_mutex_unlock(&sm->mutex);
return NULL;
}
获取互斥锁,然后通过条件变量等待状态变为5,当状态满足条件时执行相应操作,最后释放互斥锁。
- 主函数:
int main() {
StateMachine sm;
init_state_machine(&sm);
pthread_t thread;
pthread_create(&thread, NULL, thread_function, &sm);
// 主线程模拟状态转移
for (int i = 0; i < 10; i++) {
sleep(1);
transition_state(&sm, i);
if (i == 5) {
printf("Main: State set to 5, should trigger thread action.\n");
}
}
pthread_join(thread, NULL);
destroy_state_machine(&sm);
return 0;
}
初始化状态机,创建一个线程,主线程通过循环模拟状态转移,当状态转移到5时,应该触发线程的操作。最后等待线程结束并释放状态机资源。