面试题答案
一键面试数据结构设计
- 使用链表:
- 链表可以方便地进行动态插入和删除操作,适合共享资源数量动态变化的场景。例如,定义一个表示共享资源的结构体,并将其组织成链表。
struct Resource { // 资源相关数据 void* data; struct Resource* next; }; struct Resource* resource_list = NULL;
- 使用哈希表:
- 如果资源有唯一标识,可以使用哈希表来快速定位资源。在Linux下可以使用glib的
GHashTable
。 - 例如,假设资源有一个整数ID:
#include <glib.h> GHashTable* resource_hash_table = g_hash_table_new(g_direct_hash, g_direct_equal); // 插入资源 g_hash_table_insert(resource_hash_table, GINT_TO_POINTER(resource_id), resource_ptr); // 获取资源 struct Resource* resource = g_hash_table_lookup(resource_hash_table, GINT_TO_POINTER(resource_id));
- 如果资源有唯一标识,可以使用哈希表来快速定位资源。在Linux下可以使用glib的
锁策略
- 读写锁(Read - Write Lock):
- 当大部分操作是读取共享资源,而只有少数操作是修改(增加或减少资源)时,使用读写锁可以提高性能。读操作可以并发执行,写操作则需要独占锁。
#include <pthread.h> pthread_rwlock_t rwlock; pthread_rwlock_init(&rwlock, NULL); // 读操作 pthread_rwlock_rdlock(&rwlock); // 读取共享资源代码 pthread_rwlock_unlock(&rwlock); // 写操作 pthread_rwlock_wrlock(&rwlock); // 修改共享资源代码(增加或减少资源) pthread_rwlock_unlock(&rwlock);
- 细粒度锁:
- 对于链表结构的共享资源,可以为每个资源节点设置一把锁,而不是对整个链表使用一把锁。这样可以减少锁争用。
struct Resource { // 资源相关数据 void* data; struct Resource* next; pthread_mutex_t lock; }; // 访问某个资源节点 pthread_mutex_lock(&resource_node->lock); // 操作资源节点数据 pthread_mutex_unlock(&resource_node->lock);
线程调度
- 线程池:
- 使用线程池可以减少线程创建和销毁的开销,并且可以对线程进行统一调度。在Linux下可以使用
libuv
等库来实现线程池。 - 例如,使用
libuv
创建线程池:
#include <uv.h> uv_loop_t* loop = uv_default_loop(); uv_work_t work_req; // 定义工作函数 void work_callback(uv_work_t* req) { // 处理共享资源的工作 } void after_work_callback(uv_work_t* req, int status) { // 工作完成后的回调 } uv_queue_work(loop, &work_req, work_callback, after_work_callback); uv_run(loop, UV_RUN_DEFAULT);
- 使用线程池可以减少线程创建和销毁的开销,并且可以对线程进行统一调度。在Linux下可以使用
- 优先级调度:
- 根据任务的优先级来调度线程对共享资源的访问。可以为每个线程分配一个优先级,在调度时优先执行高优先级线程的任务。
- 例如,在POSIX线程中设置线程优先级:
pthread_t thread; struct sched_param param; param.sched_priority = 99; // 高优先级 pthread_setschedparam(thread, SCHED_FIFO, ¶m);
关键代码示例整合
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
// 共享资源结构体
struct Resource {
int data;
struct Resource* next;
pthread_mutex_t lock;
};
// 链表头
struct Resource* resource_list = NULL;
pthread_rwlock_t rwlock;
// 添加资源函数
void add_resource(int new_data) {
struct Resource* new_resource = (struct Resource*)malloc(sizeof(struct Resource));
new_resource->data = new_data;
new_resource->next = NULL;
pthread_mutex_init(&new_resource->lock, NULL);
pthread_rwlock_wrlock(&rwlock);
if (resource_list == NULL) {
resource_list = new_resource;
} else {
struct Resource* current = resource_list;
while (current->next != NULL) {
current = current->next;
}
current->next = new_resource;
}
pthread_rwlock_unlock(&rwlock);
}
// 删除资源函数
void delete_resource(int target_data) {
pthread_rwlock_wrlock(&rwlock);
struct Resource* current = resource_list;
struct Resource* prev = NULL;
while (current != NULL && current->data != target_data) {
prev = current;
current = current->next;
}
if (current != NULL) {
if (prev == NULL) {
resource_list = current->next;
} else {
prev->next = current->next;
}
pthread_mutex_destroy(¤t->lock);
free(current);
}
pthread_rwlock_unlock(&rwlock);
}
// 读取资源函数
void read_resource() {
pthread_rwlock_rdlock(&rwlock);
struct Resource* current = resource_list;
while (current != NULL) {
pthread_mutex_lock(¤t->lock);
printf("Resource data: %d\n", current->data);
pthread_mutex_unlock(¤t->lock);
current = current->next;
}
pthread_rwlock_unlock(&rwlock);
}
// 线程函数
void* thread_function(void* arg) {
add_resource(10);
read_resource();
delete_resource(10);
return NULL;
}
int main() {
pthread_rwlock_init(&rwlock, NULL);
pthread_t threads[10];
for (int i = 0; i < 10; i++) {
pthread_create(&threads[i], NULL, thread_function, NULL);
}
for (int i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
pthread_rwlock_destroy(&rwlock);
return 0;
}
上述代码展示了如何通过数据结构(链表)、锁策略(读写锁和细粒度锁)以及多线程操作来实现共享资源的动态管理,同时保证线程安全并减少锁争用。