我必须编写一个程序,使用4个线程模拟某些汽车的运动。他们每个人都必须从字符串中选择一辆随机的汽车,并调用一个函数来连接“ buffer_resultados”。
所有模拟功能均正常运行,问题在于每个线程都生成相同的随机数,因此每次都使用同一辆车。
另一件事是,我必须使用系统调用来打开和写入文件,因此我正在使用write()将buffer_resultados的内容写入我的.dat文件。
第一次运行良好,但是第二次没有写应该在Buffer_resultados顶部的行。
这是我的代码,我完全不熟悉C和线程,因此很可能是不正确的,谢谢。
char caracteristicas_deportivos[NUMERO_MODELOS_DEPORTIVOS][64]={"Aston Martin Vantage V12|07.7|090",
"Ferrari LaFerrari|09.6|111",
"Lamborgini Aventador|09.6|097",
"Porshe 911 turbo S|09.6|092",
"Tesla Model S|10.0|069",
"Hennessey Venom GT|10.3|120",
"Bugatti Chiron|11.2|114",
"Koenigsegg Agera|10.3|121"};
/*string que contendrá el mensaje a escribir en el fichero*/
char mensaje_final[TAM_MENSAJE_FINAL];
/* Resto del código, variables globales, funciones y función principal o main*/
//Per buffer result final
char buffer_resultados[TAM_MENSAJE_FINAL];
//Per guardar valors cotxe amb strtk_r i buffer result
char buffer_cadena[1000];
char delim[4]="|";
char cadena[1000];
char *save=cadena;
char *snom;
char *sacc;
char *svmax;
char *resultats;
double acc;
double vmax;
//Per threads
int comptador=0;
int numrandom;
//Per llegir el fitxer
ssize_t nbytes;
int descf;
//Inicialitza el semafor de threads
pthread_mutex_t mutex;
//Funcio dels THREADS
void *generar_simulacio(void* dades){
//Generem un numero random
numrandom=rand() % NUMERO_MODELOS_DEPORTIVOS;
strcpy(cadena, caracteristicas_deportivos[numrandom]); //Guardem copia caracteristicas_deportivos perque es modificara amb el strtok_r
snom=strtok_r(cadena, delim, &save);;
sacc=strtok_r(NULL, delim, &save);
svmax=strtok_r(NULL, delim, &save);
acc = atof(sacc);
vmax = atof(svmax);
//INICI ZONA EXCLUSIO MUTUA
pthread_mutex_lock(&mutex);
//#### S'inicia el semafor, aqui actua 1 sol thread alhora ####
comptador++;
char buffer_cadena[1000];
strcpy(buffer_cadena, "");
strcat(buffer_cadena, "Cotxe: ");
strcat(buffer_cadena, snom);
strcat(buffer_cadena, ", Acc: ");
strcat(buffer_cadena, sacc);
strcat(buffer_cadena, ", Vmax: ");
strcat(buffer_cadena, svmax);
strcat(buffer_cadena, ", Distancia: ");
strcat(buffer_cadena, "1000\n");
strcat(buffer_resultados, buffer_cadena); //Afegim la linia generada al buffer_resultats
movimiento_mrua(INTERVALO_TIEMPO, acc, vmax, DISTANCIA, buffer_resultados);
strcat(buffer_resultados, "\n");
//Trucada al sistema per guardar valors simulacio al fitxer
nbytes = write(descf, buffer_resultados, TAM_MENSAJE_FINAL);
if(nbytes==-1){
printf("No s'ha pogut escriure al fitxer.");
printf("%s\n", buffer_resultados);
}
else{
printf("Soc el thread n: %d. He escrit al archiu.\n", comptador);
printf("Nrand: %d \\\\ c: %s, a: %f, v: %f\n", numrandom, snom, acc, vmax);
}
//Para el semafor, tots els threads funcionen alhora
pthread_mutex_unlock(&mutex);
//FI ZONA EXCLUSIO MUTUA
strcpy(buffer_resultados, "");
}
//Inicialització del generador de numeros random
int main(int argc, char** argv){
pthread_mutex_init(&mutex,NULL);
double temps1=devolver_tiempo(); //Calcula el temps inicial per saber quan tarda en executar-se
//Obrim el fitxer
descf = open("salida_deportivos_threads.dat", O_CREAT | O_TRUNC | O_WRONLY, S_IRWXU); //O_creat crea arxiu, O_TRUNC borra tot lo de dins de l'arxiu, O_WRONLY permet escriure || S_IRWXU dona permisos a l'usuari a fer-ho tot.
if (descf == -1){
printf("Error al obrir l'archiu.\n");
}
else{
printf("Fitxer obert.\n");
}
srand(2*(time(NULL) + getpid())+1);
//Creem els 4 threads
pthread_t thread_id[2];
pthread_create(&thread_id[0], NULL,(void*)generar_simulacio,NULL);
pthread_create(&thread_id[1], NULL,(void*)generar_simulacio,NULL);
/*
if((pthread_create(&thread_id[0], NULL,(void*)generar_simulacio,NULL)!=0)||(pthread_create(&thread_id[1], NULL,(void*)generar_simulacio,NULL)!=0))
{
printf("ERROR al crear los threads \n");
return (-1);
} */
//Esperem a que tots els threads acabin
int i;
for (i=0;i<2;i++){
pthread_join(thread_id[i],NULL);
}
double temps2=devolver_tiempo();
double texecucio=(temps2-temps1)/1000000;
printf("Temps d'execucio: %.4f segons.\n", texecucio);
return(1);
}
答案 0 :(得分:1)
请注意,C11 §7.22.2.1 The rand
function不需要是线程安全的:
不需要rand函数来避免数据与伪随机序列生成函数的其他调用争用。
但是,正如Frankie_C在comment中指出的那样,您不一定直接遇到此问题-您的代码在两个线程中都使用了一个全局变量numrandom
,而没有任何使用保护(例如互斥锁,或使变量成为非全局变量)。
“显而易见”的解决方法是将numrandom
变成线程函数本地的变量(并删除现在未使用的全局变量)。
void *generar_simulacio(void* dades){
//Generem un numero random
int numrandom = rand() % NUMERO_MODELOS_DEPORTIVOS;
满足您的目的就足够了。但是,您还需要检查所有其他全局变量,并且其中大多数还需要成为线程函数中的局部变量。
严格来说,您还应该创建并使用互斥锁来保护对srand()
和rand()
的调用。或者,您需要使用备用的随机数生成器,其中每个线程可以具有自己独立的随机数序列,例如POSIX nrand48()
(或jrand48()
)。
您仍然需要种子材料的线程本地存储-除非您有非常特殊的原因要做更复杂的事情,否则这将是线程函数中的局部变量。
全局可修改变量使线程代码更难-经常使用互斥锁或某些类似的结构来协调对它们的访问以进行读写。全局常量(只读变量)不是问题。