[英]What is the best way to synchronize data when using QQuickFramebufferObject?
[英]What's the best way to synchronize this event implementation
這是我嘗試實現C ++事件。
class Event{
typedef std::tr1::function<void( int& )> CallbackFunction;
std::list< CallbackFunction > m_handlers;
template<class M>
void AddHandler(M& thisPtr, void typename (M::*callback)(int&))
{
CallbackFunction bound = std::tr1::bind(callback, &thisPtr, _1);
m_handlers.push_back(bound);
}
void operator()(int& eventArg)
{
iterate over list...
(*iter)(eventArg);
}}
這里的麻煩是線程安全。 如果同時調用AddHandler
和operator()
,事情可能會中斷。
同步這個的最佳方法是什么? 使用互斥鎖可能會降低性能。 我想知道在這種情況下boost :: signals或C#事件幕后會發生什么。
首先,在您將任何實施可能性視為“快速”不足之前,您需要確定實際的性能要求。 您是否會每秒觸發這些事件數千次? 如果你是,那么你是否真的需要一直在處理程序容器中添加處理程序。
如果這兩個問題的答案出於某種原因實際上是“是”,那么您可能需要調查無鎖容器。 這意味着構建自己的容器而不是能夠使用stl列表。 無鎖容器將使用原子內在函數(例如,在Windows中的InterlockedCompareExchange)以原子方式確定列表的末尾是否為NULL或其他。 然后,他們將使用類似的內在實際附加到列表中。 如果多個線程嘗試同時添加處理程序,則會發生其他復雜情況。
然而,在多核機器和指令重新排序等等的世界中,這些方法可能充滿危險。 我個人使用的事件系統與你描述的不同,我將它用於關鍵部分(至少在Windows中非常有效),而且我沒有遇到性能問題。 但另一方面,通過事件系統發送的任何信息都不會超過20Hz左右。
與任何與績效相關的問題一樣,答案總是基於另一個問題的答案; 你究竟在哪里需要你的表現?
互斥是你正在尋找的。 如果每個事件都有自己的互斥鎖,我不會太擔心性能; 原因在於,除非您在處理事件期間添加了大量處理程序,否則互斥體不太可能會出現爭用並使您放慢速度。
但是,如果您有多個線程在同一對象上調用operator()方法,則此互斥鎖可能會出現問題。 但是沒有它,你怎么能確保以線程安全的方式調用你的回調呢? (我注意到你傳入一個整數引用並返回void,所以我假設這些不是可重入的處理程序。)
編輯:你的評論非常好的問題。 說實話,我從未考慮過互斥是否以同步方式使用時有很多開銷。 所以我把這個小測試放在一起。
#include <stdio.h>
#include <pthread.h>
#define USE_PTHREAD_MUTEX 1
int main(int argc, char * argv[]) {
pthread_mutex_t mutex;
pthread_mutex_init(&mutex, NULL);
long useless_number = 0;
long counter;
for(counter = 0; counter < 100000000; counter++) {
#if USE_PTHREAD_MUTEX
pthread_mutex_lock(&mutex);
#endif
useless_number += rand();
#if USE_PTHREAD_MUTEX
pthread_mutex_unlock(&mutex);
#endif
}
printf("%ld\n", useless_number);
}
我在我的系統上運行了這個並獲得了以下運行時。
使用USE_PTHREAD_MUTEX 0時,平均運行時間為1.2秒。
使用USE_PTHREAD_MUTEX 1時,平均運行時間為2.8秒。
因此,回答你的問題,肯定有開銷。 你的旅費可能會改變。 此外,如果多個線程競爭訪問資源,則必須花費更多時間來阻止。 此外,在純粹的同步上下文中,與等待互斥鎖進行鎖定/解鎖相比,訪問共享資源的時間可能更長。 也就是說,與這些東西相比,互斥邏輯本身的開銷可能微不足道。
如果list真的是你的類,那么由於它的性質,你不需要每次訪問它時都鎖定。 您將鎖定互斥鎖以發布到列表的末尾,並且當您認為可能已到達結束時也會鎖定。
您應該保留類中處理程序數量的計數,當您即將開始迭代時,您可以愉快地迭代而不會鎖定,直到您達到此數字。
如果將要刪除處理程序,那么您有更多的線程爭用問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.