Qt / C ++中来自多个线程的随机函数调用

问题描述 投票:1回答:2

我有一个多线程QT应用程序,有时需要一个来自其中一个线程的随机字母数字字符串(一些线程在应用程序启动时启动,其他线程在生命周期内启动或死亡),我想通过调用一个函数来定义公共头,避免代码复制。

这里有一段代码片段:

QString generateRandomAlphanumericString(int length)
{
    qsrand(static_cast<uint>(QTime::currentTime().msec())); //bad
    QString randomAS = QString();

    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < length; ++i)
        randomAS[i] = alphanum[qrand() % (sizeof(alphanum) - 1)];

    return randomAS;
}

我最初做了一些错误。

一开始我在main函数中调用了qsrand(static_cast<uint>(QTime::currentTime().msec()));,但是I've learned它应该在每个线程中完成。

然后我把qsrand调用放在上面的函数中,但它是not correct

请注意,在程序启动时,许多线程会“一起”启动,因此如果我以当前时间(以毫秒为单位)初始化种子,则种子在它们中是相同的。

有没有办法相应地更改该函数而不修改我的应用程序中线程开始生命的所有点?在纯C ++中完成的任何实现(不使用QT)都可以。新的random C ++ 11库能以某种方式帮助实现我的任务吗?

c++ multithreading qt random
2个回答
0
投票
void InitSeedForThread(uint globalSeed, int myThreadIndex)
{
    qsrand(globalSeed);
    for (int i = 0; i < myThreadIndex; ++i)
        qrand();
}

auto GetRandom(int numThreads)
{
    for (int i = 0; i < numThreads - 1)
        qrand();
    return qrand();
}

给定一个有序的数字列表,A, B, C, D, E, F, G, H, ...将其分成n个列表。如果n是4,你会得到

1. A, E, I, ...
2. B, F, J, ...
3. C, G, K, ...
4. D, H, L, ...

骗局:做RNG有点贵,你要重复很多工作。但是,由于您正在进行QT(UI绑定),我假设性能不是问题。

或者,您可以使用互斥锁执行全局随机函数,但这也不是免费的。


0
投票

我终于找到了一个很好的解决方案(感谢所有提出意见的人):

enum ThreadData {TD_SEED};
static QThreadStorage<QHash<ThreadData, uint> *> cache;

inline void insertIntoCache(ThreadData data, uint value)
{
    if (!cache.hasLocalData())
        cache.setLocalData(new QHash<ThreadData, uint>);
    cache.localData()->insert(data, value);
}

inline void removeFromCache(ThreadData data)
{
    if (cache.hasLocalData())
        cache.localData()->remove(data);
}

inline bool hasInCache(ThreadData data)
{
    if (!cache.hasLocalData()) return false;
    return cache.localData()->contains(data);
}

inline uint getCachedData(ThreadData data)
{
    if (cache.hasLocalData() && cache.localData()->contains(data))
        return cache.localData()->value(data);
    return 0;
}

inline int getThRandom()
{
    uint seed = 0;
    if (!hasInCache(TD_SEED))
    {
        seed = QDateTime::currentMSecsSinceEpoch() % 100000000;
#ifdef Q_OS_WIN     
        seed += GetCurrentThreadId();
#else
        seed += QThread::currentThreadId();
#endif
        qsrand(static_cast<uint>(seed));
        insertIntoCache(TD_SEED, seed);
    }
    else {
        seed = getCachedData(TD_SEED);      
    }

    return qrand();
}

基本上,正如Igor所建议的,我已经使用QThreadStorage为每个线程存储种子。我已经将哈希用于未来的扩展。然后,我使用QDateTime::currentMSecsSinceEpoch()而不是QTime::currentTime().msec()在多个应用程序启动时使用不同的数字(例如,随机生成的值存储在文件/ db中并且应该不同)。然后,我使用线程ID添加了UKMonkey建议的偏移量。

所以,我原来的功能是:

QString generateRandomAlphanumericString(int length)
{
    QString randomAS = QString();

    static const char alphanum[] =
        "0123456789"
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        "abcdefghijklmnopqrstuvwxyz";

    for (int i = 0; i < length; ++i)
        randomAS[i] = alphanum[getThRandom() % (sizeof(alphanum) - 1)];

    return randomAS;
}

我已经运行了一些测试,从不同的线程生成数千个字母数字字符串,将它们存储到多个文件中,并在它们之间以及多个应用程序运行之间进行双重检查。

© www.soinside.com 2019 - 2024. All rights reserved.