面试题答案
一键面试任务调度方面
- 难题
- 负载均衡:在多核环境下,如何将任务合理分配到不同核心上,避免某个核心负载过重,而其他核心闲置,C语言本身没有内置自动处理负载均衡的机制。例如,若手动分配任务不合理,可能导致系统整体性能下降,某些实时任务无法按时完成。
- 实时性保证:多核系统中任务调度复杂度增加,C语言开发者需要精确控制任务的优先级和执行时间,以满足实时性要求。但C语言缺乏对任务实时调度的直接支持,如很难直接定义任务的截止时间等实时属性。
- 解决方案
- 负载均衡:可以使用任务队列和调度算法。例如,采用轮询调度算法,将任务依次分配到不同核心。代码示例:
#include <stdio.h>
#include <pthread.h>
#define CORES 4
#define TASKS 10
// 任务结构体
typedef struct {
int task_id;
} Task;
// 任务队列
Task task_queue[TASKS];
int queue_index = 0;
// 线程函数
void* worker(void* arg) {
int core_id = *((int*)arg);
while (1) {
if (queue_index < TASKS) {
Task task = task_queue[queue_index++];
printf("Core %d is processing task %d\n", core_id, task.task_id);
} else {
break;
}
}
return NULL;
}
int main() {
pthread_t cores[CORES];
int core_ids[CORES];
for (int i = 0; i < CORES; i++) {
core_ids[i] = i;
pthread_create(&cores[i], NULL, worker, &core_ids[i]);
}
for (int i = 0; i < TASKS; i++) {
task_queue[i].task_id = i;
}
for (int i = 0; i < CORES; i++) {
pthread_join(cores[i], NULL);
}
return 0;
}
- 实时性保证:可以使用实时操作系统(RTOS),如FreeRTOS。在FreeRTOS中,C语言开发者可以通过定义任务优先级、周期等属性来保证任务实时性。例如:
#include "FreeRTOS.h"
#include "task.h"
// 任务函数
void vTaskFunction(void *pvParameters) {
for (;;) {
// 任务执行代码
vTaskDelay(pdMS_TO_TICKS(100)); // 任务延迟100毫秒
}
}
int main() {
xTaskCreate(vTaskFunction, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
vTaskStartScheduler();
return 0;
}
数据共享与同步方面
- 难题
- 数据竞争:多核同时访问和修改共享数据时,可能导致数据不一致。例如多个核心同时对一个全局变量进行自增操作,由于操作不是原子的,可能导致结果错误。
- 死锁:当多个任务需要获取多个同步资源时,如果获取顺序不当,可能会导致死锁。例如任务A获取资源1并等待资源2,任务B获取资源2并等待资源1,就会形成死锁。
- 解决方案
- 数据竞争:使用互斥锁(Mutex)。互斥锁可以保证在同一时间只有一个核心能访问共享数据。例如:
#include <stdio.h>
#include <pthread.h>
int shared_variable = 0;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 线程函数
void* increment(void* arg) {
pthread_mutex_lock(&mutex);
shared_variable++;
pthread_mutex_unlock(&mutex);
return NULL;
}
int main() {
pthread_t threads[10];
for (int i = 0; i < 10; i++) {
pthread_create(&threads[i], NULL, increment, NULL);
}
for (int i = 0; i < 10; i++) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&mutex);
printf("Final value: %d\n", shared_variable);
return 0;
}
- 死锁:使用资源分配图算法(如银行家算法)预防死锁,或者采用资源获取顺序固定的策略。以信号量为例,假设任务需要获取多个信号量,按固定顺序获取。例如:
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
sem_t sem1, sem2;
// 线程1函数
void* thread1_function(void* arg) {
sem_wait(&sem1);
sem_wait(&sem2);
// 访问共享资源
sem_post(&sem2);
sem_post(&sem1);
return NULL;
}
// 线程2函数
void* thread2_function(void* arg) {
sem_wait(&sem1);
sem_wait(&sem2);
// 访问共享资源
sem_post(&sem2);
sem_post(&sem1);
return NULL;
}
int main() {
sem_init(&sem1, 0, 1);
sem_init(&sem2, 0, 1);
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread1_function, NULL);
pthread_create(&thread2, NULL, thread2_function, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}
通过按相同顺序获取信号量,可以避免死锁。