4

考虑你有一个列表:

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() -> wait),必须有多个条件变量(我错了吗?)

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

4

1 回答 1

1

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

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

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

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

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

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

通过上述解决方案,所有的依赖关系都被分离出来了,任务也得到了精简。

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

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

更新:

我的回答最初提出以下内容:

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

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

于 2013-03-20T19:50:25.523 回答