Jacob
Jacob

Reputation: 1

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?

Upvotes: 0

Views: 99

Answers (2)

WhozCraig
WhozCraig

Reputation: 66194

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.

Upvotes: 1

selbie
selbie

Reputation: 104524

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.

Upvotes: 1

Related Questions