我正试图想出一个快速解决以下问题的方法:
我有一个产生数据的线程,以及几个使用它的线程。我不需要对生成的数据进行排队,因为数据生成的速度比消耗的慢得多(即使偶尔不是这种情况,如果偶尔跳过数据点也不会有问题)。所以,基本上,我有一个封装“最新状态”的对象,只允许生产者线程更新。
我的策略如下(如果我完全脱离摇杆,请告诉我):
我为这个例子创建了三个类:SharedObject<Thing>
(实际的状态对象),SharedObjectManager<Thing>
(一个对象,可以是每个线程的本地对象,并赋予该线程对底层Thing的访问权限) )和shared_ptr
,其中包含mutex
和SharedObjectManager
。
SharedObject<Thing>
(SOM)的实例是一个全局变量。
当生产者启动时,它会实例化Thing,并告诉全局SOM。然后它制作一份副本,并对该副本进行所有更新工作。当它准备提交它对Thing的更改时,它会将新Thing传递给全局SOM,后者锁定它的互斥锁,更新它保留的共享指针,然后释放锁。
同时,消费者线程全部变为shared_ptr
。这些对象每个都保留一个指向全局SOM的指针,以及由SOM保存的update()
的缓存副本......它保持缓存,直到显式调用#include <mutex>
#include <iostream>
#include <memory>
class Thing
{
private:
int _some_member = 10;
public:
int some_member() const { return _some_member; }
void some_member(int val) {_some_member = val; }
};
// one global instance
template<typename T>
class SharedObjectManager
{
private:
std::shared_ptr<T> objPtr;
std::mutex objLock;
public:
std::shared_ptr<T> get_sptr()
{
std::lock_guard<std::mutex> lck(objLock);
return objPtr;
}
void commit_new_object(std::shared_ptr<T> new_object)
{
std::lock_guard<std::mutex> lck (objLock);
objPtr = new_object;
}
};
// one instance per consumer thread.
template<typename T>
class SharedObject
{
private:
SharedObjectManager<T> * som;
std::shared_ptr<T> cache;
public:
SharedObject(SharedObjectManager<T> * backend) : som(backend)
{update();}
void update()
{
cache = som->get_sptr();
}
T & operator *()
{
return *cache;
}
T * operator->()
{
return cache.get();
}
};
// no actual threads in this test, just a quick sanity check.
SharedObjectManager<Thing> glbSOM;
int main(void)
{
glbSOM.commit_new_object(std::make_shared<Thing>());
SharedObject<Thing> myobj(&glbSOM);
std::cout<<myobj->some_member()<<std::endl;
// prints "10".
}
。
我相信这很难理解,所以这里有一些代码:
// initialization - on startup
auto firstStateObj = std::make_shared<Thing>();
glbSOM.commit_new_object(firstStateObj);
// main loop
while (1)
{
// invoke copy constructor to copy the current live Thing object
auto nextState = std::make_shared<Thing>(*(glbSOM.get_sptr()));
// do stuff to nextState, gradually filling out it's new value
// based on incoming data from other sources, etc.
...
// commit the changes to the shared memory location
glbSOM.commit_new_object(nextState);
}
生产者线程使用的想法是:
SharedObject<Thing> thing(&glbSOM);
while(1)
{
// think about the data contained in thing, and act accordingly...
doStuffWith(thing->some_member());
// re-cache the thing
thing.update();
}
消费者的使用将是:
{
"title":"Biology",
"content":"Egg period: 4 -6 days \n
Eggs laid in cracks and crevices of the loose bark on the trunk \n
Eggs: ovoid or elliptical and dirty white in colour \n
Adult :Reddish brown in colour",
"isSubtitle":"N"
}
谢谢!
答案 0 :(得分:1)
这是过度工程的方式。相反,我建议做以下事情:
Thing* theThing
的指针。可以是全局的,也可以是其他方式共享的。将其初始化为nullptr。Thing
类型的两个本地对象 - Thing thingOne
和Thing thingTwo
(请记住,thingOne
并不比thingTwo
好,但是因为某种原因被称为thingOne
,但这是件事。请注意猫。)。首先填充thingOne
。完成后,锁定互斥锁,将thingOne
地址复制到theThing
,解锁互斥锁。开始填充thingTwo
。完成后,请参见上文。重复直至死亡。theThing
指向的对象的副本。解锁互斥锁。使用您的副本。阅后即焚。重复直至死亡。