事情似乎有效,但我不確定這是否是最好的方式。從另一個線程修改向量中的指針數據是否安全?
基本上我有一個異步檢索數據的對象。該對象具有在主線程上分配和解除分配的指針向量。使用boost函數,一個進程結果回調與這個向量中的一個指針綁定。當它觸發時,它將在一些任意線程上運行並修改指針的數據。
現在我有部分圍繞推入矢量和擦除以防異步檢索對象收到更多請求的情況下的關鍵部分,但我想知道是否需要在修改指針的回調中使用某種警戒數據也是如此。
希望這個瘦身僞代碼使事情變得更加清晰:
class CAsyncRetriever
{
// typedefs of boost functions
class DataObject
{
// methods and members
};
public:
// Start single asynch retrieve with completion callback
void Start(SomeArgs)
{
SetupRetrieve(SomeArgs);
LaunchRetrieves();
}
protected:
void SetupRetrieve(SomeArgs)
{
// ...
{ // scope for data lock
boost::lock_guard<boost::mutex> lock(m_dataMutex);
m_inProgress.push_back(SmartPtr<DataObject>(new DataObject)));
m_callback = boost::bind(&CAsyncRetriever::ProcessResults, this, _1, m_inProgress.back());
}
// ...
}
void ProcessResults(DataObject* data)
{
// CALLED ON ANOTHER THREAD ... IS THIS SAFE?
data->m_SomeMember.SomeMethod();
data->m_SomeOtherMember = SomeStuff;
}
void Cleanup()
{
// ...
{ // scope for data lock
boost::lock_guard<boost::mutex> lock(m_dataMutex);
while(!m_inProgress.empty() && m_inProgress.front()->IsComplete())
m_inProgress.erase(m_inProgress.begin());
}
// ...
}
private:
std::vector<SmartPtr<DataObject>> m_inProgress;
boost::mutex m_dataMutex;
// other members
};
編輯:這是ProccessResults回調的實際代碼(加上您的利益評論)
void ProcessResults(CRetrieveResults* pRetrieveResults, CRetData* data)
{
// pRetrieveResults is delayed binding that server passes in when invoking callback in thread pool
// data is raw pointer to ref counted object in vector of main thread (the DataObject* in question)
// if there was an error set the code on the atomic int in object
data->m_nErrorCode.Store_Release(pRetrieveResults->GetErrorCode());
// generic iterator of results bindings for generic sotrage class item
TPackedDataIterator<GenItem::CBind> dataItr(&pRetrieveResults->m_DataIter);
// namespace function which will iterate results and initialize generic storage
GenericStorage::InitializeItems<GenItem>(&data->m_items, dataItr, pRetrieveResults->m_nTotalResultsFound); // this is potentially time consuming depending on the amount of results and amount of columns that were bound in storage class definition (i.e.about 8 seconds for a million equipment items in release)
// atomic uint32_t that is incremented when kicking off async retrieve
m_nStarted.Decrement(); // this one is done processing
// boost function completion callback bound to interface that requested results
data->m_complete(data->m_items);
}
如果您希望得到明智的答案,您需要添加更多信息。目前很重要的一點是缺失,特別是'SomeMethod','IsComplete'是什麼以及如何實現以及* complete *標誌如何產生。如果處理函數的最後一行是一個賦值,除非這是用戶定義的類型,並且它被鎖定,並且它是將「IsComplete」設置爲true的那個,否則答案是否定的,這是不安全的。但我的猜測是,這個處理函數只是一個骨架。 – 2011-06-10 23:03:15
是啊,這是一個很大的框架,我只是想表明它調用方法並在其中指定成員。在這一點上,我認爲只要每個指針的每個回調只有一個線程的語義保持不變,我就會好起來的。增量異步檢索引入了太多的延遲,所以我並不擔心該實現。 – AJG85 2011-06-10 23:08:59
這種方法本身並沒有什麼錯,但魔鬼在細節中。根據實際操作是什麼以及如何對* shared *數據執行同步(我的猜測是共享數據只是一個由'IsComplete'檢查的標誌),那麼它可能是正確的。無論是最好的方法還是可以簡化的方法都是一個不同的問題,但沒有上下文就無法說清楚。可能很重要的事情是:'SmartPtr'線程安全的實現?那裏的競賽條件很有可能。 – 2011-06-11 10:10:37