假设您有一个列表:
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() 获取共享锁(互斥锁,私有(private)锁)。 除此之外,您还希望能够通过 getDataFromClient() 从客户端获取数据。
如果客户端在其队列中根本没有数据,getDataFromClient() 将等待该客户端的条件变量,直到它有新数据要读取。
好吧,这是我的问题:
只要 getDataFromClient();等待,(因为这是一个多读者/单作者列表),我无法添加新客户端或删除客户端,因为 getDataFromClient() 持有互斥锁。
如果您有一个列表,您将如何准确解决该场景,该列表应该是线程安全的 + 等待特定客户端的条件变量 + 在等待客户端时,能够删除或添加其中包含的任何客户端名单?
所以这里又是事实:
- 线程安全列表(多个读者/单个作者)
- 能够随时添加/删除客户
- 能够专门为每个客户端等待一个(特定的)条件(一个客户端可能已经在他自己的队列中存储了新数据,而另一个没有;然后 getDataFromClient() 将等待直到有新数据被读取)
我认为的问题是,鉴于每个客户端都有一个条件(伪代码:if(clientsqueue.isEmpty() -> wait)必须有多个条件变量(我错了吗?)
更多信息:
操作系统:Windows 7
语言:C++
编译器VS2010
最佳答案
您的设置非常糟糕。您有一个由 Clients
类表示的表,以及多个 CLIENTOBJ
实例,每个实例都充当表的一行,id
充当首要的关键。然而,据我了解,每个客户端实际上是一个数据队列。
数据库使用的模型可以粗略地描述为将对数据的任何访问委托(delegate)给数据库中的专用事件(线程或进程),并使用 SQL 向其发送命令。同步问题是通过事务和 SQL 子句处理的(如果所寻找的 id
不存在,则更新可能不会影响任何行,但该命令不会失败,它只会返回 0 行更新) .在您的情况下,类似的模型可能会很有趣:只有一个全局互斥锁来表示事务,每个线程锁定整个数据结构,对其进行操作,然后解锁。但是,这可能不是很有效。
异步等价物是让每个命令返回一个 std::future
而不是真正的结果。从那时起,线程只需要等待 future
,并在它完成(或因异常而中断)时对其进行操作。
在Clients
实例中,任何方法调用都被转换为future
和promise
。 promise 被推送到 promise 队列,调用线程要么从方法调用中获取 future ,要么立即等待它。
从数据库进程的角度来看,这是一项顺序工作:您有一个 promise 队列,所有其他线程将数据与它必须去的客户端 ID 捆绑在一起推送到该队列。然后数据库线程按顺序满足生成的 promise :
- 创建一个新客户
- 删除一个客户
- 如果它是一个存储,数据库线程检查是否有任何读取挂起,并满足它,或者只是将该数据放入客户端队列
- 如果是读取并且有数据,则从客户端队列中将其拉出并交给线程,或者将其推送到客户端的挂起读取队列,以便稍后在数据可用时满足。
通过上述解决方案,分离了所有依赖项并简化了任务。
您也可以为每个 CLIENTOBJ
分配一个线程。然后 DB 线程变成一个分类线程,它简单地将 promise 分发给每个客户端。每个客户端都拥有给定 id
的待处理读取和数据队列,因此在处理 promises 时不涉及锁。
每个队列都必须用一个互斥锁保护,这意味着主 promise 队列有 1 个互斥锁,每个客户端 promise 队列有 1 个互斥锁,条件变量与使用 Clients
方法的线程一样多.
更新:
我的回答最初提出以下建议:
In other words, you could replace the future/promise mechanism by a simple condition variable associated to each non DB threads (future and promise are probably implemented using a cond. variable, but here you would save the creation and destruction overhead).
但它对 CLIENTS
对象的使用方式做了一些隐含的假设。最安全的道路确实是 std::future
道路。
关于c++ - 共享列表、多个条件、一个或多个条件变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15531358/