[英]Is it safe to call a signal function of a widget class in Qt from multiple threads in 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.