1

I am looking to generate random values for 3 threads running in a freeRTOS environment. Knowing that rand() is not thread-safe I use a mutex to protect it. In addition, I call srand() only once. What should I consider when trying to solve this issue?

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#include "FreeRTOS.h"
#include "semphr.h"

#include "sensorDriver.h"

SemaphoreHandle_t semaphoreMutexDriver; 
uint16_t sensorValue; 

void sensorDriver_initialize()
{
    srand(time(NULL));
    semaphoreMutexDriver = xSemaphoreCreateMutex();
}

void getValue()
{
    if (xSemaphoreTake(semaphoreMutexDriver, portMAX_DELAY))
    {
        sensorValue = (uint16_t)(rand() % 50);
        xSemaphoreGive(semaphoreMutexDriver);
    }
}

uint16_t sensorDriver_getValue()
{
    getValue();

    return sensorValue;
}

More code can be added upon request.

UPDATE 1

Tried making the sensorValue local to the function, like that:

uint16_t firstSensorDriver_getValue()
{
    if (xSemaphoreTake(semaphoreMutexDriver, portMAX_DELAY))
    {
        uint16_t sensorValue = (uint16_t)(rand() % 50);
        xSemaphoreGive(semaphoreMutexDriver);

        return sensorValue;
    }
}

Did not do the trick (if better suggestions implementation wise, please do not hesitate), also the thread puts the value into a struct after getting it, not sure if this helps. (each thread in its own struct).

UPDATE 2

Here is the struct and how the value is saved:

struct firstSensor
{
     uint16_t firstSensorValue;
     EventGroupHandle_t meassureEventGroup;
     EventGroupHandle_t dataReadyEventGroup;
};


void firstSensor_fetchSensorValue(FirstSensor self)
{
     self->firstSensorValue = sensorDriver_getValue();
}

UPDATE 3

Here is an example of the first and second thread/struct implementation

#ifndef FIRSTSENSOR_H
#define FIRSTSENSOR_H

typedef struct firstSensor* FirstSensor; 

FirstSensor firstSensor_create(UBaseType_t taskPriority, EventGroupHandle_t 
eventGroupMeassure, EventGroupHandle_t eventGroupDataReady);
uint16_t firstSensor_getSensorValue(FirstSensor self);
void firstSensor_destroySensor(FirstSensor self);

#endif

and similarly second thread header and source file

#ifndef SECONDSENSOR_H
#define SECONDSENSOR_H

typedef struct secondSensor* SecondSensor; 

SecondSensor secondSensor_create(UBaseType_t taskPriority, EventGroupHandle_t             
eventGroupMeassure, EventGroupHandle_t eventGroupDataReady);
uint16_t secondSensor_getSensorValue(SecondSensor self);
void secondSensor_destroySensor(SecondSensor self);

#endif

And implementation

struct secondSensor
{
     uint16_t secondSensorValue;
     EventGroupHandle_t meassureEventGroup;
     EventGroupHandle_t dataReadyEventGroup;
};

void secondSensor_fetchSensorValue(SecondSensor self)
{
    self->secondSensorValue = firstSensorDriver_getValue();
}

void secondSensor_task(void* instance)
{
    EventBits_t eventBitsMeasure;
    SecondSensor self = (SecondSensor*)instance;

    for (;;)
    {
        eventBitsMeasure = xEventGroupWaitBits(self->meassureEventGroup, BIT_SECOND_SENSOR, pdTRUE, pdTRUE, portMAX_DELAY);

        if ((eventBitsMeasure & BIT_SECOND_SENSOR) == BIT_SECOND_SENSOR)
        {
            secondSensor_fetchSensorValue(self);
            xEventGroupSetBits(self->dataReadyEventGroup, BIT_SECOND_SENSOR);
        }
    }
}

UPDATE 4 Well technically they are random for each emm, run so to say, but they are same within the same run. Picture below on the left is what my small program is printing on the right simple random print. enter image description here

UPDATE 5

Another weird thing is that everytime I run the code I get the same sequence of numbers as if stand is never called (even though it is), even if I seed the srand() with time(NULL) + clock() which should be different everytime. Maybe it can help...

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
el-aasi
  • 307
  • 2
  • 18
  • 2
    Are you saving the result in `sensorValue`? the global variable is shared among all threads, they will see the same value, last generated value. – Tony Tannous May 12 '20 at 14:12
  • I will try that and tell you how it works. – el-aasi May 12 '20 at 14:14
  • Where is that struct defined? – Tony Tannous May 12 '20 at 14:23
  • @TonyTannous did not work :( at least not how I understood, I updated the question if it is not what you meant please, elaborate – el-aasi May 12 '20 at 14:24
  • I suspect the struct your saving to, is also shared by all threads. Make the struct local to each thread. – Tony Tannous May 12 '20 at 14:24
  • Does each thread has it's own `FirstSensor`? where are you defining it ? – Tony Tannous May 12 '20 at 14:27
  • @TonyTannous no, each thread has its own struct, I will post further how I define them – el-aasi May 12 '20 at 14:28
  • Write a simple script, print the return from rand() function. 10 times in a while loop. Is it printing the same value? – Tony Tannous May 12 '20 at 14:36
  • `time`'s resolution is too big as it measures in seconds, try using something with nanoseconds resolution. https://stackoverflow.com/a/58150904/8298811 – isrnick May 12 '20 at 15:59
  • @isrnick you might be right, but I just realized that in the small rand() print program done on side, the sequence was the same as in my little program only because I have forgotten to call the srand() (I will update the topic) so it acts as if srand() wasn't called (even though when checking with a print it is called, one time upon launching). – el-aasi May 12 '20 at 16:03
  • @isrnick tried with clock() as suggested in the post, same values of each thread/same sequence – el-aasi May 12 '20 at 16:07

1 Answers1

0

so, not sure entirely why, yet, it only worked only if srand() was called 3 times (each time the task runs, but outside the infinite loop so that it runs only once, in the function that xTaskCreate is provided with upon creation of the task) instead only once in the main(). If it was called only once in the main function, the random values were as if the srand() function was never called. I suppose (only suppose, don't have any evidence yet) that it is because of the fact that each task has its own stack.

Thanks to everyone assisting in the troubleshooting...

el-aasi
  • 307
  • 2
  • 18