簡體   English   中英

在Qt / C ++中從多個線程進行隨機函數調用

[英]Random function call from multiple threads in Qt/C++

我有一個多線程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;
}

我最初犯了一些錯誤。

一開始我叫qsrand(static_cast<uint>(QTime::currentTime().msec())); 在main函數中,但我了解到應該按線程完成。

然后我將qsrand調用放在上面的函數中,但這是不正確的

請考慮在程序啟動時許多線程“一起”啟動,因此如果我以毫秒為單位的當前時間初始化種子,則它們之間的種子是相同的。

有沒有一種方法可以相應地更改該功能,而無需修改我的應用程序中線程開始運行的所有點? 在純C ++中完成的任何實現(不使用QT)都可以。 新的random C ++ 11庫能否以某種方式幫助完成我的任務?

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綁定),因此我認為性能不是問題。

或者,您可以使用互斥量執行全局隨機函數,但這也不是免費的。

我終於找到了一個很好的解決方案(感謝發表評論的每個人):

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中並且應該有所不同)。 然后,按照UKMonkey的建議,使用線程ID添加一個偏移量。

因此,我的原始功能將是:

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;
}

我進行了一些測試,從不同的線程中生成數千個字母數字字符串,將它們存儲到多個文件中,並仔細檢查它們之間以及在多個應用程序運行之間是否存在重復。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM