面试题答案
一键面试设计思路
- 细粒度锁:将文件划分成多个较小的区域,每个区域使用独立的锁进行保护。这样不同线程可以同时访问文件的不同区域,减少锁争用。
- 读写锁优化:对于读操作,可以允许多个线程同时进行,而写操作则需要独占锁。因此,使用读写锁(
pthread_rwlock
)可以提高并发读的性能。 - 锁缓存:为每个线程维护一个锁缓存,线程在访问文件区域时,先检查自己的锁缓存中是否已经持有对应的锁,避免重复获取锁的开销。
可能用到的数据结构
- 锁数组:用于存储每个文件区域对应的锁。例如,可以使用一个
pthread_rwlock_t
类型的数组,数组大小根据文件划分的区域数量而定。
#define REGION_COUNT 10
pthread_rwlock_t lock_array[REGION_COUNT];
- 线程本地存储(TLS):用于存储每个线程的锁缓存。可以使用
pthread_key_t
来创建线程本地存储。
pthread_key_t lock_cache_key;
- 锁缓存数据结构:可以使用一个简单的数组或者哈希表来存储线程已经持有的锁。这里以数组为例:
typedef struct {
int is_locked[REGION_COUNT];
} LockCache;
关键的同步代码
- 初始化部分
void init_locks() {
for (int i = 0; i < REGION_COUNT; ++i) {
pthread_rwlock_init(&lock_array[i], NULL);
}
pthread_key_create(&lock_cache_key, NULL);
}
- 获取锁
void acquire_lock(int region_id) {
LockCache *cache = (LockCache *)pthread_getspecific(lock_cache_key);
if (cache == NULL) {
cache = (LockCache *)malloc(sizeof(LockCache));
memset(cache->is_locked, 0, sizeof(cache->is_locked));
pthread_setspecific(lock_cache_key, cache);
}
if (!cache->is_locked[region_id]) {
pthread_rwlock_wrlock(&lock_array[region_id]);
cache->is_locked[region_id] = 1;
}
}
- 释放锁
void release_lock(int region_id) {
LockCache *cache = (LockCache *)pthread_getspecific(lock_cache_key);
if (cache != NULL && cache->is_locked[region_id]) {
pthread_rwlock_unlock(&lock_array[region_id]);
cache->is_locked[region_id] = 0;
}
}
- 读操作
void read_file_region(int region_id) {
acquire_lock(region_id);
// 进行读操作
release_lock(region_id);
}
- 写操作
void write_file_region(int region_id) {
acquire_lock(region_id);
// 进行写操作
release_lock(region_id);
}
- 清理部分
void cleanup_locks() {
for (int i = 0; i < REGION_COUNT; ++i) {
pthread_rwlock_destroy(&lock_array[i]);
}
pthread_key_delete(lock_cache_key);
}
通过以上设计和代码实现,可以有效地减少多线程读写同一文件时的锁争用,提高整体性能。