面试题答案
一键面试选择最佳switch参数类型
- 简单类型优先:如果状态判断主要基于简单数据类型(如整数、枚举),优先选择这些类型作为switch参数。因为简单类型处理起来效率高,在多线程环境下资源竞争相对容易控制。例如,对于具有有限状态的状态机,可以定义枚举类型:
enum class State {
STATE_INIT,
STATE_RUNNING,
STATE_FINISHED
};
然后在switch语句中使用:
State currentState = State::STATE_INIT;
switch (currentState) {
case State::STATE_INIT:
// 初始化逻辑
break;
case State::STATE_RUNNING:
// 运行逻辑
break;
case State::STATE_FINISHED:
// 完成逻辑
break;
}
- 自定义类对象:当状态判断依赖于自定义类对象时,需要确保该类重载了
operator==
,并且尽量简化类的结构,减少不必要的数据成员,以降低资源竞争风险。例如:
class MyClass {
public:
int value;
bool operator==(const MyClass& other) const {
return value == other.value;
}
};
MyClass obj;
obj.value = 10;
switch (obj) {
case MyClass{5}:
// 处理逻辑
break;
case MyClass{10}:
// 处理逻辑
break;
}
- 联合类型:联合类型可以节省内存,但使用时要特别小心。确保在多线程环境下对联合成员的访问是线程安全的。例如:
union MyUnion {
int intValue;
float floatValue;
};
MyUnion u;
u.intValue = 10;
switch (u.intValue) {
case 5:
// 处理逻辑
break;
case 10:
// 处理逻辑
break;
}
多线程环境下的资源竞争和数据一致性问题
- 互斥锁(Mutex):使用
std::mutex
来保护共享资源。在访问可能导致资源竞争的状态变量前,先锁定互斥锁,访问完成后解锁。例如:
#include <mutex>
std::mutex stateMutex;
State globalState = State::STATE_INIT;
void threadFunction() {
std::lock_guard<std::mutex> lock(stateMutex);
switch (globalState) {
case State::STATE_INIT:
// 处理逻辑
break;
// 其他状态处理
}
}
- 原子操作:对于简单类型的状态变量,可以使用原子类型(如
std::atomic
)来避免使用互斥锁带来的性能开销。例如:
#include <atomic>
std::atomic<State> atomicState(State::STATE_INIT);
void threadFunction() {
State current = atomicState.load();
switch (current) {
case State::STATE_INIT:
// 处理逻辑
break;
// 其他状态处理
}
}
优化思路
- 减少锁的粒度:尽量缩小互斥锁保护的代码范围,只在真正需要保护共享资源的地方加锁。
- 状态缓存:在每个线程中缓存一份状态副本,减少对共享状态变量的访问频率。但要注意在状态更新时及时同步缓存。
- 无锁数据结构:对于复杂数据结构,可以考虑使用无锁数据结构,如无锁队列、无锁哈希表等,以提高多线程性能。