我正在编写一个线程应用程序,它将处理资源列表,并且可能会或可能不会将结果项放置在每个资源的容器(std::map)中。资源的处理发生在多个线程中。
将遍历结果容器,每个项目由一个单独的线程处理,该线程接受一个项目并更新 MySQL 数据库(使用 mysqlcppconn API),然后从容器中删除该项目并继续。
为简单起见,这里是逻辑的概述:
queueWorker() - thread
getResourcesList() - seeds the global queue
databaseWorker() - thread
commitProcessedResources() - commits results to a database every n seconds
processResources() - thread x <# of processor cores>
processResource()
queueResultItem()
以及显示我在做什么的伪实现。
/* not the actual stucts, but just for simplicities sake */
struct queue_item_t {
int id;
string hash;
string text;
};
struct result_item_t {
string hash; // hexadecimal sha1 digest
int state;
}
std::map< string, queue_item_t > queue;
std::map< string, result_item_t > results;
bool processResource (queue_item_t *item)
{
result_item_t result;
if (some_stuff_that_doesnt_apply_to_all_resources)
{
result.hash = item->hash;
result.state = 1;
/* PROBLEM IS HERE */
queueResultItem(result);
}
}
void commitProcessedResources ()
{
pthread_mutex_lock(&resultQueueMutex);
// this can take a while since there
for (std::map< string, result_item_t >::iterator it = results.begin; it != results.end();)
{
// do mysql stuff that takes a while
results.erase(it++);
}
pthread_mutex_unlock(&resultQueueMutex);
}
void queueResultItem (result_item_t result)
{
pthread_mutex_lock(&resultQueueMutex);
results.insert(make_pair(result.hash, result));
pthread_mutex_unlock(&resultQueueMutex);
}
如 processResource() 所示,问题就在那里,当 commitProcessedResources() 正在运行并且 resultQueueMutex 被锁定时,我们将在这里等待 queueResultItem() 返回,因为它会尝试锁定相同的互斥体,因此会等待直到完成,这可能需要一段时间。
显然,由于运行的线程数量有限,因此一旦所有线程都在等待 queueResultItem() 完成,在互斥锁被释放并可用于 queueResultItem() 之前,将不再进行任何工作。
所以,我的问题是我如何最好地实现这一点?是否有一种特定类型的标准容器可以同时插入和删除,或者是否存在我不知道的东西?
每个队列项都可以拥有自己的唯一键并不是绝对必要的,就像 std::map 的情况一样,但我更喜欢它,因为多个资源可以产生相同的结果,我更愿意只发送一个唯一的结果到数据库,即使它确实使用 INSERT IGNORE 忽略任何重复项。
不幸的是,我对 C++ 还很陌生,所以我不知道在 Google 上要寻找什么。:(