【问题标题】:Shared list, multiple conditions, one or more condition variables?共享列表、多个条件、一个或多个条件变量?
【发布时间】:2013-03-20 18:02:52
【问题描述】:

假设您有一个列表:

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() 持有互斥锁。

如果您有一个列表,您将如何准确解决该场景,该列表应是线程安全的 + 等待特定客户端的条件变量 + 在等待客户端时,能够删除或添加其中包含的任何客户端名单?

所以这里再一次是事实:

  • 线程安全列表(多读/单写)
  • 能够随时添加/删除客户端
  • 能够专门等待每个客户端的(特定)条件(一个客户端可能在自己的队列中存储了新数据,而另一个没有;然后 getDataFromClient() 将等待直到有新数据被读取)

我认为的问题是,鉴于每个客户端都有一个条件(伪代码:if(clientsqueue.isEmpty() -> 等待)必须有多个条件变量(我错了吗?)

更多信息:
操作系统:Windows 7
语言:C++
编译器VS2010

【问题讨论】:

  • 语言:C++?我永远不会猜到。
  • @EtiennedeMartel:那我可以建议你走错了职业道路吗?

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


【解决方案1】:

您的设置非常DBish。您有一个由Clients 类表示的表,以及CLIENTOBJ 的几个实例,每个实例都充当表的一行,id 充当主键。然而,据我了解,每个客户端实际上都是一个数据队列。

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

异步等效是让每个命令返回一个std::future,而不是真正的结果。从那时起,线程只需要在future 上等待,并在它完成(或异常中断)时对其进行操作。

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

从 DB 进程的角度来看,这是一项连续的工作:您有一个承诺队列,所有其他线程都将与客户端 ID 捆绑在一起的数据推送到该队列中。然后DB线程按顺序满足生成的promise:

  • 创建一个新客户端
  • 删除客户端
  • 如果是存储,则 DB 线程会检查是否有任何读取处于待处理状态,并满足它,或者只是将该数据放入客户端队列中
  • 如果是读取且有数据,则从客户端队列中拉取并交给线程,或者将其推送到客户端的待处理读取队列中,以便稍后数据可用时满足。

通过上面的解决方案,所有的依赖都被分离了,任务被精简了。

您还可以为每个CLIENTOBJ 指定一个线程。然后 DB 线程变成了一个分类线程,它简单地将 Promise 分发给每个客户端。每个客户端都拥有给定id 的待处理读取和数据队列,因此在处理 Promise 时不涉及锁。

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

更新:

我的回答最初提出如下:

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

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

【讨论】:

  • 好吧,在对您的答案进行了足够长的思考/试图理解它之后,我将尝试未来/承诺的解决方案,因为在这种情况下它似乎是最好的解决方案。非常感谢。
  • 对不起,如果这听起来很复杂,我尝试使用 DB 比喻(可能是因为我当时对 DB 的东西很感兴趣),我似乎有点接受它。又读了一遍,有点懵。这个想法实际上是让一个专用线程或线程池处理CLIENTS 类,这实际上是一个客户端管理器。线程异步处理任何请求,并将其结果作为未来返回,以便调用活动同时执行其他操作。
  • 另一个比喻是处理多个客户帐户的公司:您可以让一个人处理所有事情(我称之为 DB 线程),或者整个员工队伍,每个帐户一个人,这次 DB 线程只充当中间人。
猜你喜欢
  • 1970-01-01
  • 2021-02-19
  • 2018-03-09
  • 1970-01-01
  • 2015-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多