面试题答案
一键面试使用rand()在多线程中可能遇到的问题
- 线程安全问题:标准库的
rand()
函数不是线程安全的。在多线程环境下,多个线程同时调用rand()
可能会导致竞争条件,因为rand()
通常依赖于一个内部的静态状态(如种子),多个线程同时访问和修改这个静态状态会产生未定义行为。
解决方案
- 每个线程使用独立的种子:为每个线程生成一个独立的种子,这样每个线程就有自己独立的随机数生成序列,避免了竞争。可以使用线程局部存储(TLS)来实现。
代码示例
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <time.h>
// 线程局部存储变量,每个线程有自己独立的种子
_Thread_local unsigned int seed;
// 线程执行函数
void* generate_random(void* arg) {
// 使用线程ID作为种子的一部分生成唯一种子
long thread_id = (long)arg;
seed = (unsigned int)(time(NULL) + thread_id);
// 生成并打印10个随机数
for (int i = 0; i < 10; ++i) {
int random_number = rand_r(&seed) % 100;
printf("Thread %ld: Random number %d: %d\n", thread_id, i, random_number);
}
return NULL;
}
int main() {
const int num_threads = 3;
pthread_t threads[num_threads];
// 创建线程
for (long i = 0; i < num_threads; ++i) {
if (pthread_create(&threads[i], NULL, generate_random, (void*)i) != 0) {
perror("pthread_create");
return 1;
}
}
// 等待所有线程完成
for (int i = 0; i < num_threads; ++i) {
if (pthread_join(threads[i], NULL) != 0) {
perror("pthread_join");
return 2;
}
}
return 0;
}
在这段代码中:
- 使用
_Thread_local
关键字声明了一个线程局部变量seed
,每个线程都有自己独立的种子。 - 在每个线程的执行函数
generate_random
中,根据线程ID和当前时间为每个线程生成唯一的种子。 - 使用
rand_r
函数来生成随机数,rand_r
是rand
的线程安全版本,它需要一个指向种子的指针作为参数。 - 在
main
函数中创建多个线程并等待它们完成。