Generating and printing random numbers using threads in C++ - c++

I'm currently working on a project which requires the use of threads. However, before tackling the project, I want to create a simple exercise for myself to test my understanding of threads.
What I have are 2x functions; one for infinitely generating random numbers and the other for printing the output of this function.
The value of this random number will be continuously updated via a pointer.
From my understanding, I will need a mutex to prevent undefined behavior when reading and writing values to this pointer. I would also need to detach the random number generator function from the main function.
However, I'm having issues trying to build the project in Visual Studio Code which I suspecting due to a flaw in my logic.
#include <bits/stdc++.h>
#include <iostream>
#include <thread>
#include <mutex>
std::mutex global_mu;
void generateRandomNum(int min, int max, int *number)
{
while (true) {
global_mu.lock();
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(min, max);
*number = uni(rng);
global_mu.unlock();
}
}
int main()
{
int *int_pointer;
int number = 0;
int_pointer = &number;
std::thread t1(generateRandomNum, 0, 3000, int_pointer);
t1.detach();
while(true) {
global_mu.lock();
std::cout << int_pointer << std::endl;
global_mu.unlock();
}
}

This looks wrong:
std::cout << int_pointer << std::endl;
You're trying to print the value of the pointer instead of printing the value of the int variable to which it points. You either should do this:
std::cout << *int_pointer << std::endl;
or this:
std::cout << number << std::endl;
This also looks like it maybe does not do what you want:
while (true) {
...
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(min, max);
*number = uni(rng);
...
}
You are constructing and initializing a new random number generator for each iteration of the loop. You probably should move the PRNG out of the loop:
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(min, max);
while (true) {
...
*number = uni(rng);
...
}
Finally, you probably should not ever do this:
while(true) {
global_mu.lock();
...
global_mu.unlock();
}
What's the very next thing that the thread does after it calls unlock()? The next thing it does is, it re-locks the same mutex again.
I don't want to get too technical, but the problem in this situation is that the thread that is most likely to acquire the mutex will be the one that just released it, and not the one that's been waiting for a long time. Whichever thread gets in to the mutex first, is going to starve the other thread.
The way out of the starvation problem is to only lock the mutex for the least amount of time necessary. E.g.,:
void generateRandomNum(int min, int max, int *number)
{
std::random_device rd;
std::mt19937 rng(rd());
std::uniform_int_distribution<int> uni(min, max);
while (true) {
int temp = uni(rng);
global_mu.lock();
*number = temp;
global_mu.unlock();
}
}
int main()
{
int *int_pointer;
int number = 0;
int_pointer = &number;
std::thread t1(generateRandomNum, 0, 3000, int_pointer);
t1.detach();
while(true) {
int temp;
global_mu.lock();
temp = number;
global_mu.unlock();
std::cout << temp << std::endl;
}
}
If this feels like you're writing a lot of extra lines, you're right. Multi-threading is hard to get right. And, in order to get high performance from a multi-threaded program, you are going to have to write extra lines of code, and maybe even make the program do more work per CPU than a single threaded program would do.

Related

Improper usage of mutex c++

i have problem with my code. This function pushes a product into queue.
void producent(bool &cont,std::queue<std::string> &queue,std::mutex &mtx, int &milliseconds)
{
while (cont)
{
mtx.lock();
if (queue.size() >= MAX_QUEUE_SIZE)
{
mtx.unlock();
std::cerr << "buffor full " << std::endl;
}
else
{
std::string product = generate();
std::cerr << "producent: " << product << " " << std::endl;
queue.push(product);
mtx.unlock();
}
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}
}
this function generates a string of 10 signs, which are pushed by void producent function().
std::string generate() {
std::string temp;
temp.resize(10);
for (int i = 0; i < 10; i++) {
temp[i] = rand() % ('z' - 'a' + 1) + 'a';
}
return temp;
}
My question is: why, when i create 2 threads like this:
std::thread prod(producent, std::ref(wykonuj),std::ref(kolejka), std::ref(kolejka_mtx),std::ref(t));
std::thread prod1(producent, std::ref(wykonuj), std::ref(kolejka), std::ref(kolejka_mtx), std::ref(t));
both of them give me same result, for example the outcome is:
producent: qweasdzxca
producent: qweasdzxca
i wanted those outcomes to be different, thats why i used mutex, but it didnt work. Can someone give me some advices?
rand doesn't share a seed between threads. Each thread has its own seed - but without explicitly setting it differently in both threads via srand(), it's going to be the same.
Hence, generate invoked by both threads will produce the same string.
The docs suggest rand_r is the thread safe version, but both functions are threads safe in modern implementations.
Assuming your implementation has a thread-safe rand() (probably unwise), both threads are using the same initial random seed (the default of 1, in this case), and thus producing the same sequence. Rather than doing that, embrace the the C++ <random> offerings, and as far as that goes, the uniform distribution offerings as well.
#include <algorithm>
#include <random>
#include <string>
std::string generate(int n=10)
{
std::mt19937 prng{ std::random_device{}() };
std::uniform_int_distribution<int> dist('a', 'z');
std::string result;
std::generate_n(std::back_inserter(result), n, [&]() { return dist(prng); });
return result;
}
Executed 10x on 10x threads, this produced:
ysudtdcaeq
hwpeyiyyav
dlsdshltyo
pkfafhooxr
nmoxerbqpy
ydauzdvoaj
brjqjgxrgg
ezdsmbhygb
fpdgbkxfut
elywaokbyv
That, or something similar, should produce what you seek.
Note: the above will not work as-expected on platforms where a..z is non-contiguous. If you're on such a beast (typically OS/400 or OS/390 EBCDIC), an alternate solution is required.

C++ generate random number every time

I need to make a simulator for a college homework. In this simulator there are 3 computers, 2 of which send messages to computer 1 which then decides to either send the message or reject it. The rejection is random chance with 20% of rejection on computer 2 and 50% on computer 3. I use the rand()%100+1 function with the srand(time(NULL)) seed. It makes a random number however I need to run this multiple times and every time the same random number is used. For example if I run the simulation 12 times and the number generated is 45, 45 is used 12 times. I've both placed the random number generator inside the code and made a function outside.
How can you make a random number generator that generates a random number every time?
#include <iostream>
#include <new>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
using namespace std;
int randomgen()
{
int rndnum=0;
srand (time(NULL));
rndnum=rand()%100+1;
cout<< rndnum<<endl;
return rndnum;
}
struct comp1
{
int rejected=0;
int received=0;
int sent=0;
int onhold=0;
bool comp2reception()
{
received++;
bool result=false;
int rndnum=0;
srand (time(NULL));
rndnum=rand()%100+1;
if(rndnum<=20)
{
rejected++;
result=false;
}
if(rndnum>=21)
{
onhold++;
result=true;
}
return result;
}
bool comp3reception()
{
received++;
bool result=false;
int rndnum=randomgen;
if(rndnum<=50)
{
rejected++;
result=false;
}
if(rndnum>=51)
{
onhold++;
result=true;
}
return result;
}
};
Use the C++11 header <random>.
#include <random>
static std::random_device rd;
static std::mt19937 gen(rd());
int randomgen()
{
std::uniform_int_distribution<> dis(0,100);
int rndnum = dis(gen);
std::cout << rndnum << std::endl;
return rndnum;
}
Call srand(time(NULL)) just once at the beginning of the program.
Since time() return number of seconds from 1970 and you program probably takes less than that to finish, you esentially reset the generator with same value before each call. Which of course returns same (first) value each call.

Execute code x percent of the time

I have an animal that lives in a while loop for many days.
At the end of the day, there is a 40% chance she gives birth,
class Animal
{
public:
double chance_of_birth;
...
public Animal(..., int chance)
{
this.chance_of_birth = chance;
...
}
}
// create this animal
Animal this_animal = new Animal(..., .50);
Given that every animal I create can have a specific chance of giving birth,
how can I write a condition that evaluates true only chance_of_birth percent of the time?
I know I want to use rand(), but I never used it like this before.
Along the lines of
if(this_animal->chance_of_birth ???)
{
//will give birth
}
Since c++11 you can use the library <random>. In the example below I'm using std::uniform_real_distribution<> to generate a random floating point value within the range 0 - 1
#include <iostream>
#include <random>
using namespace std;
double random(int min, int max)
{ // we make the generator and distribution 'static' to keep their state
// across calls to the function.
std::random_device rd;
static std::mt19937 gen(rd());
static std::uniform_real_distribution<> dis(min, max);
return dis(gen);
}
int main()
{
double f = random(0,1); // range 0 - 1
cout << f << '\n';
}
Now you can use that random floating point value in an if statement to run only when a condition is true.
if (f <= 0.40) { ... }

Random Generator, seed not working

I want to create a class that will return a random number whenever I call it. But when I put it into a loop it returns the same random number each time. I am seeding it once but it still returns the same one over and over again. Its only when I close out of the program and open it again itll be different. Any help would be much appreciated.
**EDIT
When I cant see how I am calling it every time.
RadomGenerator rg = new...
for(int i =0; i<10; i++){
rg.createRandomNumber(1,5);}
Is this not instansiating the seed only once then calling the method createRandomNumber several times?
RandomGenerator::RandomGenerator()
{
seed = time(0);
}
int RandomGenerator::createRandomNumber(int start, int end)
{
std::function<int()> randomNumber = std::bind(std::uniform_int_distribution<int>(start,end),
mt19937(seed));
qDebug()<< "result" << randomNumber() ;
return randomNumber();
}
You're seeding it every single time.
#include <random>
struct RandomGenerator {
std::mt19937 _engine;
std::uniform_int_distribution<int> _dist;
RandomGenerator(int start, int end)
: _engine { std::random_device{} () },
_dist(start, end)
{
}
int createRandomNumber()
{
return _dist(_engine);
}
};
Note that it's actually not useful to create an instance of uniform_*_distribution for a single call either.
Let alone, wrapping that in a function<>.
You can usually use a
auto mygen = bind(, );
Instead of that whole class, and use it:
int this_is_random = mygen();
In C++14:
auto mygen = [ _engine = mt19937{ random_device{}() }, _dist = uniform_int_distribution<>(12, 42) ]() mutable {
return _dist(_engine);
};
See it Live On Coliru
Is this not instansiating the seed only once then calling the method createRandomNumber several times?
No. In this line you instantiate a mt19937 each time with the same seed:
std::function<int()> randomNumber = std::bind(std::uniform_int_distribution<int>(start,end),
mt19937(seed));

Parallel execution doesn't update my variable

I want to write a program where, random numbers are going to be created and I am going to track down the greatest of them. Two threads are going to run in parallel. However, my best variable is stuck at its initial variable. Why?
[EDIT]
I updated the code after Joachim's answer, but I am not getting the correct answer at every run! What am I missing?
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
#include <random>
std::default_random_engine generator((unsigned int)time(0));
int random(int n) {
std::uniform_int_distribution<int> distribution(0, n);
return distribution(generator);
}
std::mutex mtx; // mutex for critical section
void update_cur_best(int& cur_best, int a, int b) {
// critical section (exclusive access to std::cout signaled by locking mtx):
mtx.lock();
if(a > b)
cur_best = a;
else
cur_best = b;
mtx.unlock();
}
void run(int max, int& best) {
for(int i = 0; i < 15; ++i) {
int a = random(max); int b = random(max);
update_cur_best(best, a, b);
mtx.lock();
std::cout << "|" << a << "| |" << b << "|" << std::endl;
mtx.unlock();
}
}
int main ()
{
int best = 0;
std::thread th1 (run, 100, std::ref(best));
std::thread th2 (run, 100, std::ref(best));
th1.join();
th2.join();
std::cout << "best = " << best << std::endl;
return 0;
}
Sample output:
|4| |21|
|80| |75|
|93| |95|
|4| |28|
|52| |92|
|96| |12|
|83| |8|
|4| |33|
|28| |35|
|59| |52|
|20| |73|
|60| |96|
|61| |34|
|67| |79|
|67| |95|
|54| |57|
|20| |75|
|40| |30|
|16| |32|
|25| |100|
|33| |36|
|69| |26|
|94| |46|
|15| |57|
|50| |68|
|9| |56|
|46| |70|
|65| |65|
|76| |73|
|16| |29|
best = 29
I am getting 29, which is not the maximum!
As an answer to the updated question, in update_cur_best the value of best is overwritten on each iteration. In the end, its value will simply be the greater of the most recent a, b pair generated. What you want to do is update it only when the current a or b is greater than best (I'm not sure why you generate two random values on each iteration...)
It's because you can't really pass references to the thread constructor, because they will not be passed on as references, but copied and it's those copies that are passed to your thread function. You have to use std::ref to wrap the reference.
E.g.
std::thread th1 (run, 100, std::ref(best));