共享列表,多个条件,一个或多个条件变量?

时间:2013-03-20 18:02:53

标签: c++ multithreading list shared condition-variable

考虑一下你有一个清单:

class CLIENTS
{
public:

    CLIENTS();
    ~CLIENTS();

    bool addClient();
    bool removeClient();
    bool getDataFromClientObj(unsigned int id);
    bool storeDataInClientObj(unsigned int id);
private:

    // vector, that contains all the clients
    boost::ptr_vector<CLIENTOBJ> clients;

    // mutex for the client-list
    boost::mutex mutex;
};

进一步考虑,getDataFromClientObj()获取共享锁(互斥锁,私有)。 除此之外,您希望能够通过getDataFromClient()从客户端获取数据。

如果客户端队列中根本没有数据,则getDataFromClient()将等待该客户端的条件变量,直到它有新的数据要读取。

嗯,这是我的问题:
只要getDataFromClient();等待,(因为这是一个多读者/单一作者列表),我无法添加新客户端或删除客户端,因为getDataFromClient()持有互斥锁。

如果你有一个列表,你将如何准确地解决这个场景,那就是线程安全+等待特定客户端的条件变量+在客户端等待时,能够删除或添加任何一个客户端清单?

所以这又是事实:

  • Threadsafe List(多个读者/单个作者)
  • 能够随时添加客户端/删除客户端
  • 能够特定地等待每个客户端的(特定)条件(一个客户端可能已将新数据存储在自己的队列中,而另一个客户端未存储;然后getDataFromClient()将等待直到新数据被读取)

我认为问题是,假设每个客户端都有一个条件(伪代码:if(clientsqueue.isEmpty() - &gt; wait),必须有多个条件变量(我错了吗?)

进一步资料:
操作系统:Windows 7
语言:C ++
编译器VS2010

1 个答案:

答案 0 :(得分:1)

您的设置非常糟糕。你有一个由Clients类表示的表,以及CLIENTOBJ的几个实例,每个实例都像表的一行,id作为主键。但据我所知,每个客户端实际上都是一个数据队列。

数据库使用的模型可以粗略地描述为将对数据的任何访问权限委托给db中的专用活动(线程或进程),并使用SQL向其发送命令。使用事务和SQL子句处理同步问题(如果查找的id不存在,更新可能不会影响任何行,但该命令不会失败,它只会返回0行更新)。在您的情况下,类似的模型可能会很有趣:只有一个全局互斥体来表示事务,每个线程锁定整个数据结构,操作它并解锁。但是,这可能效率不高。

异步等价物是让每个命令返回std::future而不是实际结果。从那时起,线程只需要在future上等待,并在它完成时对其进行操作(或者在例外情况下被破坏)。

Clients实例中,任何方法调用都会转换为futurepromise。承诺被推送到一个承诺队列,调用线程要么从方法调用中获取未来,要么立即等待它。

从数据库进程的角度来看,这是一个顺序工作:你有一个promise队列,所有其他线程都将所有其他线程推送到必须去的客户端id捆绑的数据。然后,DB线程按顺序满足结果承诺:

  • 创建新客户
  • 删除客户
  • 如果是商店,数据库线程会检查是否有任何读取待处理,并且满足它,或者只是将该数据放入客户端队列中
  • 如果它是一个读取数据,那么将它从客户端队列中拉出并将其提供给线程,或者将其推送到客户端的挂起读取队列,以便稍后在数据可用时满足。

通过上述解决方案,所有依赖关系都是分开的,并且任务得以简化。

您还可以为CLIENTOBJ专用一个帖子。然后,DB线程成为一个分类线程,它只是将promises分发给每个客户端。每个客户端拥有给定id的待处理读取和数据队列,因此处理承诺时不会涉及锁定。

每个队列必须使用互斥锁进行保护,这意味着主承诺队列为1个互斥锁,每个客户端承诺队列为1个互斥锁,以及使用Clients方法的线程数量多于条件变量。

更新

我的回答最初提出以下建议:

  

换句话说,您可以通过与每个非DB线程关联的简单条件变量替换future / promise机制(future和promise可能使用cond。变量实现,但在这里您可以节省创建和销毁开销)

但它对CLIENTS对象的使用方式做了一些隐含的假设。最安全的道路确实是std::future道路。