事情似乎有效,但我不确定这是否是最好的方式。从另一个线程修改向量中的指针数据是否安全?
基本上我有一个异步检索数据的对象。该对象具有在主线程上分配和解除分配的指针向量。使用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