C-产生相同随机值的线程

时间:2018-12-15 17:25:44

标签: c multithreading pthreads

我必须编写一个程序,使用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);
}

1 个答案:

答案 0 :(得分:1)

请注意,C11 §7.22.2.1 The rand function不需要是线程安全的:

  

不需要rand函数来避免数据与伪随机序列生成函数的其他调用争用。

但是,正如Frankie_Ccomment中指出的那样,您不一定直接遇到此问题-您的代码在两个线程中都使用了一个全局变量numrandom,而没有任何使用保护(例如互斥锁,或使变量成为非全局变量)。

“显而易见”的解决方法是将numrandom变成线程函数本地的变量(并删除现在未使用的全局变量)。

void *generar_simulacio(void* dades){   
    //Generem un numero random
    int numrandom = rand() % NUMERO_MODELOS_DEPORTIVOS;

满足您的目的就足够了。但是,您还需要检查所有其他全局变量,并且其中大多数还需要成为线程函数中的局部变量。

严格来说,您还应该创建并使用互斥锁来保护对srand()rand()的调用。或者,您需要使用备用的随机数生成器,其中每个线程可以具有自己独立的随机数序列,例如POSIX nrand48()(或jrand48())。 您仍然需要种子材料的线程本地存储-除非您有非常特殊的原因要做更复杂的事情,否则这将是线程函数中的局部变量。

全局可修改变量使线程代码更难-经常使用互斥锁或某些类似的结构来协调对它们的访问以进行读写。全局常量(只读变量)不是问题。