Thread: Using srand() in multicore code.

  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    13

    Using srand() in multicore code.

    Hi all,

    I've wrote this code to generate 8 random numbers. i'll get each core to generate one random number each.

    I'm using the OpenMP extension of the GCC compiler here for the code to enable the use of multiple threads with the use of pragmas(plus other things which are not in use here).

    Everything encased in the parentheses after " #pragma omp parallel private(th_id)" is split into 8 mirror copies, one for each core. Work for each core can be assigned and changed by creating if statements that only allows a specific core id, declared "th_id" to be passed and thus allow only certain code to run on a certain core.

    Picture all 8 logical CPU cores running this code.
    Notice that all eight if statements are running at the very same time.

    Now I'm using rand() in each of these cores. if i seeded with srand() once, it would tell rand() to produce a pesudo-random number based on the system clock, HOWEVER all cores are running in parallel at the same time. meaning the random number is the same for each core. Hence this is why i'm seeding in each if statement, therefore each core, with an offset so i don't end up with the same numbers.

    It works but what's got me thinking is that the random numbers are not changing every time i evoke rand(). they seem to change once every second.

    Is there a way to get the random numbers to generate faster?
    Every time i use rand()?. It's really the whole idea here, using multiple threads and all.

    Soz for the lengthy explanation, gotta try a visualize this nicely.

    Code:
    #include<stdio.h>
    #include<omp.h>
    #include<windows.h>
    #include<stdlib.h>
    
    main()
    {
    int th_id,x0,x1,x2,x3,x4,x5,x6,x7;
    
    #pragma omp parallel private(th_id)
    {
    	srand(time(NULL));   /*x = (rand() % (max - min + 1) + min);*/
    
    	while(1)
    	{
    
    	//---------------INDIVIDUAL THREAD TASKS RUNNING IN PARALLEL-----------------
    		th_id = omp_get_thread_num();
    		if(th_id==0)
    		{
    			srand(time(NULL)+1);
    			x0 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==1)
    		{
    			srand(time(NULL)+2);
    			x1 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==2)
    		{
    			srand(time(NULL)+3);
    			x2 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==3)
    		{
    			srand(time(NULL)+4);
    			x3 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==4)
    		{
    			srand(time(NULL)+5);
    			x4 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==5)
    		{
    			srand(time(NULL)+6);
    			x5 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==6)
    		{
    			srand(time(NULL)+7);
    			x6 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==7)
    		{
    			srand(time(NULL)+8);
    			x7 = (rand() % (7 - 1 + 1) + 1);
    		}
    	//----------------------------------------------------------------------------
    	printf("%d%d%d%d%d%d%d%d\n",x0,x1,x2,x3,x4,x5,x6,x7);
    	}
    
    } //end of parallel section
    
    }

  2. #2
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    seed with something else...
    Perhaps "time(NULL)/th_id" ?

    ^That would probably not be very effective
    Consider clock() ; ..if you need faster changes as you said.
    Last edited by manasij7479; 12-01-2011 at 05:56 AM.

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    13
    clock() is a good idea.

    trying to seed srand() with the result of clock().

    seem right?

    not exactly getting the desired result. all random numbers are the same. but I think i'm closer.

    Code:
    #include<stdio.h>
    #include<omp.h>
    #include<windows.h>
    #include<stdlib.h>
    #include<time.h>
    main()
    {
    int th_id,x0,x1,x2,x3,x4,x5,x6,x7;
    clock_t start_0,start_1,start_2,start_3,start_4,start_5,start_6,start_7,stop_0,stop_1,stop_2,stop_3,stop_4,stop_5,stop_6,stop_7;
    double duration_0,duration_1,duration_2,duration_3,duration_4,duration_5,duration_6,duration_7;
     
    
    
    #pragma omp parallel private(th_id)
    {
    	srand(time(NULL));   /*x = (rand() % (max - min + 1) + min);*/
    
    	while(1)
    	{
    
    	//---------------INDIVIDUAL THREAD TASKS RUNNING IN PARALLEL-----------------
    		th_id = omp_get_thread_num();
    		if(th_id==0)
    		{
    			start_0 = clock();
    		}
    		if(th_id==1)
    		{
    			start_1 = clock();
    		}
    		if(th_id==2)
    		{
    			start_2 = clock();
    		}
    		if(th_id==3)
    		{
    			start_3 = clock();
    		}
    		if(th_id==4)
    		{
    			start_4 = clock();
    		}
    		if(th_id==5)
    		{
    			start_5 = clock();
    		}
    		if(th_id==6)
    		{
    			start_6 = clock();
    		}
    		if(th_id==7)
    		{
    			start_7 = clock();
    		}
    		
    		if(th_id==0)
    		{
    			stop_0 = clock();  // get number of ticks after loop
    			duration_0 = ( double ) ( stop_0 - start_0 ) / CLOCKS_PER_SEC;
    			srand(duration_0);
    			x0 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==1)
    		{
    			stop_1 = clock();  // get number of ticks after loop
    			duration_1 = ( double ) ( stop_1 - start_1 ) / CLOCKS_PER_SEC;
    			srand(duration_1);
    			x1 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==2)
    		{
    			stop_2 = clock();  // get number of ticks after loop
    			duration_2 = ( double ) ( stop_2 - start_2 ) / CLOCKS_PER_SEC;
    			srand(duration_2);
    			x2 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==3)
    		{
    			stop_3 = clock();  // get number of ticks after loop
    			duration_3 = ( double ) ( stop_3 - start_3 ) / CLOCKS_PER_SEC;
    			srand(duration_3);
    			x3 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==4)
    		{
    			stop_4 = clock();  // get number of ticks after loop
    			duration_4 = ( double ) ( stop_4 - start_4 ) / CLOCKS_PER_SEC;
    			srand(duration_4);
    			x4 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==5)
    		{
    			stop_5 = clock();  // get number of ticks after loop
    			duration_5 = ( double ) ( stop_5 - start_5 ) / CLOCKS_PER_SEC;
    			srand(duration_5);
    			x5 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==6)
    		{
    			stop_6 = clock();  // get number of ticks after loop
    			duration_6 = ( double ) ( stop_6 - start_6 ) / CLOCKS_PER_SEC;
    			srand(duration_6);
    			x6 = (rand() % (7 - 1 + 1) + 1);
    		}
    		if(th_id==7)
    		{
    			stop_7 = clock();  // get number of ticks after loop
    			duration_7 = ( double ) ( stop_7 - start_7 ) / CLOCKS_PER_SEC;
    			srand(duration_7);
    			x7 = (rand() % (7 - 1 + 1) + 1);
    		}
    	//----------------------------------------------------------------------------
    	printf("%d%d%d%d%d%d%d%d\n",x0,x1,x2,x3,x4,x5,x6,x7);
    	}
    
    } //end of parallel section
    
    }

  4. #4
    Registered User Codeplug's Avatar
    Join Date
    Mar 2003
    Posts
    4,981
    The problem is that srand/rand are not "thread-safe".

    Either call rand() prior to your parallel section, or use your own RNG which is thread-safe.

    gg

  5. #5
    Registered User
    Join Date
    May 2009
    Posts
    4,183
    I would try seeding it only once (not inside the thread); but, Codeplug is more likely to be right.

    Tim S.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    The first thing to remember is that your machine is a lot faster than any of the standard clocks, so the result of things like time(NULL) will basically appear to be a constant for a great many loops.

    Second, after some reading, it might be implied that each core gets a separate copy of the libc data section due to some magic caused by linking with the openmp flags.

    You could test this by calling say asctime, which returns a pointer to some internal data, and seeing if you get a different pointer from each core. If you do, your libc data has been cloned, and you can rand() all you want on each thread, and not worry about what other threads are up to.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Algorithm Dissector iMalc's Avatar
    Join Date
    Dec 2005
    Location
    New Zealand
    Posts
    6,318
    Unless you're specificically reseeding the PRNG for the purposes of replaying the same sequence played previously (like when playing back a saved game), it is always wrong to call srand more than once.
    First make sure you are using a PRNG that uses thread local storage, i.e. each threads generator is completely independent. Then seed once, when the thread is created, based on a hash of the time and the thread id.

    Then all that's left to do is just repeatedly call rand()
    My homepage
    Advice: Take only as directed - If symptoms persist, please see your debugger

    Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"

  8. #8
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    The problem is that srand() and rand() make use of some static storage, and access to that static storage needs to be synchronised.

    You need to create a lock - aka mutex using omp_init_lock() - to protect srand() and rand(). Then every thread grabs the lock (omp_set_lock()) before calling rand() and releases it (omp_unset_lock()) after calling rand(). Preferably only call srand() once - before launching threads.

    This will work regardless of whether each thread gets its own local copy of libc, or if you have access to a rand() and srand() that employs thread-local storage. The disadvantage is that threads are forced to wait on each other every time they seek a value from rand().
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    13
    I guess since rand() and srand() isn't very thread safe, or needing to use locks for them i decided to use a simple RNG.

    I made a function for each thread. Each function been a pseudorandom number generator. Not the best random number gen I've used but it uses all threads. (below).

    Code:
    #include<stdio.h>
    #include<time.h>
    #include<windows.h>
    #include <omp.h>
    
    int random_num_0(int lim)
    {
    static long a = 1; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_1(int lim)
    {
    static long a = 2; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_2(int lim)
    {
    static long a = 3; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_3(int lim)
    {
    static long a = 4; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_4(int lim)
    {
    static long a = 5; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_5(int lim)
    {
    static long a = 6; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_6(int lim)
    {
    static long a = 7; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    int random_num_7(int lim)
    {
    static long a = 8; // could be made the seed value
     
    a = (a * 32719 + 3) % 32749;
    return ((a % lim) + 1);
    }
    
    main()
    {
    int x,th_id,count;
    count=0;
    int RND_0,RND_1,RND_2,RND_3,RND_4,RND_5,RND_6,RND_7;
    #pragma omp parallel private(th_id)
    {
    	th_id = omp_get_thread_num();
    	
    	while(1)
    	{
    		//printf("count value:%d",count);
    		{
    			RND_0=random_num_0(9);
    			printf("%d",RND_0);
    		}
    		if(th_id==1)
    		{
    			RND_1=random_num_1(9);
    			printf("%d",RND_1);
    		}
    		if(th_id==2)
    		{
    			RND_2=random_num_2(9);
    			printf("%d",RND_2);
    		}
    		if(th_id==3)
    		{
    			RND_3=random_num_3(9);
    			printf("%d",RND_3);
    		}
    		if(th_id==4)
    		{
    			RND_4=random_num_4(9);
    			printf("%d",RND_4);
    		}
    		if(th_id==5)
    		{
    			RND_5=random_num_5(9);
    			printf("%d",RND_5);
    		}
    		if(th_id==6)
    		{
    			RND_6=random_num_6(9);
    			printf("%d",RND_6);
    		}
    		if(th_id==7)
    		{
    			RND_7=random_num_7(9);
    			printf("%d",RND_7);
    		}
    		
    	}
    }
    printf("\n\n***end of program***");
    }

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. HELP with srand(time()( in Code::Blocks (C language)
    By Italikus in forum C Programming
    Replies: 4
    Last Post: 06-22-2011, 02:06 PM
  2. help with srand()
    By ~C_Student~ in forum C Programming
    Replies: 10
    Last Post: 12-22-2009, 10:55 AM
  3. Replies: 2
    Last Post: 07-19-2009, 12:54 AM
  4. srand
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 02-26-2002, 06:06 AM
  5. srand help
    By Unregistered in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 12-15-2001, 09:14 PM