C+的线程同步+;地图 我用pTrice(C++ 98标准)创建了一个多线程C++程序。

C+的线程同步+;地图 我用pTrice(C++ 98标准)创建了一个多线程C++程序。,c++,multithreading,dictionary,pthreads,C++,Multithreading,Dictionary,Pthreads,我有一个多线程将访问的std::map。访问将使用find添加和删除元素,并使用[]操作符访问元素 我知道使用[]操作符读取,甚至用它修改元素都是线程安全的,但其余的操作不是 第一个问题:我理解正确吗 一些线程将仅通过[]访问元素,而其他线程将执行一些其他操作。显然,我需要某种形式的线程同步 我认为这应该是可行的: -虽然没有对映射执行“写入”操作,但所有线程都应该能够同时从映射中“读取”。 -当一个线程想要“写入”映射时,它应该设置一个锁,这样就不会有线程启动任何“读取”或“写入”操作,然后它

我有一个多线程将访问的std::map。访问将使用find添加和删除元素,并使用[]操作符访问元素

我知道使用[]操作符读取,甚至用它修改元素都是线程安全的,但其余的操作不是

第一个问题:我理解正确吗

一些线程将仅通过[]访问元素,而其他线程将执行一些其他操作。显然,我需要某种形式的线程同步

我认为这应该是可行的: -虽然没有对映射执行“写入”操作,但所有线程都应该能够同时从映射中“读取”。 -当一个线程想要“写入”映射时,它应该设置一个锁,这样就不会有线程启动任何“读取”或“写入”操作,然后它应该等到所有“读取”操作完成,在这一点上它将执行该操作并释放锁。 -释放锁后,所有线程都应该能够自由读取

主要问题是:我可以使用什么线程同步方法来实现这种行为

我读过关于互斥、条件变量和信号量的书,据我所知,它们并不能满足我的需要。我熟悉互斥,但不熟悉cond。变量或信号量

我看到的主要问题是,我需要一种方法来锁定线程,直到发生某些事情(写入操作结束),而没有这些线程,然后依次锁定任何东西。 此外,我还需要一个倒过来的信号量,当计数器大于1时阻塞,然后当计数器为0时唤醒(即没有执行读取操作)

提前谢谢

这是我的第一篇文章。请指出我是否做错了什么

我知道使用
[]
操作符读取,甚至用它修改元素都是线程安全的,但其余的操作不是

我理解正确吗

嗯,你说的不太对。并发读卡器可以使用
[]
访问现有的元素,或者使用其他
常量
函数(如
查找
大小()
…),如果没有同时执行的非
常量
操作,如
擦除
插入
变异
映射
。并发线程可以修改不同的元素,但是如果一个线程修改了一个元素,那么在另一个线程尝试访问或进一步修改该特定元素之前,您必须进行一些同步

当一个线程想要“写入”映射时,它应该设置一个锁,这样就不会有线程启动任何“读取”或“写入”操作,然后它应该等到所有“读取”操作完成,在这一点上它将执行该操作并释放锁。-释放锁后,所有线程都应该能够自由读取

这不是它的工作方式。。。为了使写入程序能够“等待所有“读取”操作完成”,读卡器需要获得一个锁。然后,编写者等待同一个锁被释放,并自行获取该锁以限制其他读者或编写者,直到他们完成更新并释放它

我可以使用什么线程同步方法来实现这种行为

互斥锁确实是合适的,尽管读写器锁通常会获得更高的性能(它允许并发读写器,有些还优先于其他读写器)。相关POSIX线程函数包括:,等等

为了对比这两种方法,读者和作者使用互斥,您可以得到如下序列化:

THREAD   ACTION
reader1  pthread_mutex_lock(the_mutex) returns having acquired lock, and
         thread starts reading data
reader2  pthread_mutex_lock(the_mutex) "hangs", as blocked by reader1
writer1  pthread_mutex_lock(the_mutex) hangs, as blocked by reader1
reader1  pthread_mutex_unlock(the_mutex) -> releases lock
NOTE: some systems guarantee reader2 will unblock before writer1, some don't
reader2  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,
         and thread starts reading data
reader1  pthread_mutex_lock(the_mutex) hangs, as blocked by reader2
reader2  pthread_mutex_unlock(the_mutex) -> releases lock    
writer1  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,
         and thread starts writing and/or reading data
writer1  pthread_mutex_unlock(the_mutex) -> releases lock    
reader1  blocked pthread_mutex_lock(the_mutex) returns having acquired lock,
         and thread starts reading data
...etc...
对于读写锁,它可能更像这样(注意前两个读卡器同时运行):


你只需要一个读写互斥锁吗?你需要一个RW锁,试试看第一篇文章。你确定不能用吗?它将简化您的代码,并使其更具可移植性。根据容器元素的性质,您可能不需要较重的线程特性。也许原语就足够了。@BrettHale:不能使用c++11,因为它运行在一个旧平台上,而我无法为其重建工具链。读/写锁确实是我所需要的。我不知道他们!谢谢。根据具体情况,多版本并发可能是一种选择,例如可以通过将
共享\u ptr
放入映射而不是对象本身来实现。读卡器复制共享指针,编写器以原子方式将其替换为另一个指针。因此,被读取的对象在地图中的生存期超过它们的存在期,直到不再需要它们为止。请注意,围绕共享指针进行复制并不完全是“免费的”,这可能比读写器锁定更快或更慢,具体取决于您的操作。@Damon:好建议-可能属于单独的答案,或者直接在问题下进行评论。。。?当然由你决定。干杯。“并发读者可以使用[]访问现有元素”不,没有这样的运气。根据§17.6.5.9/3(N3376),允许实现在任何非
const
方法中修改对象,并且
操作符[]
甚至没有
const
重载。因此,它在同一对象上的并发使用会导致未定义的行为。安全的替代方法包括
at()
const
重载、
find()
下限()
,严格来说,这意味着类似于
const\u cast(map.at)(key)
的内容,而不仅仅是转换非
const
at()的结果到
映射类型::常量迭代器
@ArneVogel:
[]
的效果定义为“如果
映射中没有与
x
等价的键,则在
映射中插入
值类型(x,T())
”(类似于
&
),不需要插入时不指定效果,
THREAD   ACTION
reader1  pthread_rwlock_rdlock(the_rwlock) returns having acquired lock, and
         thread starts reading data
reader2  pthread_rwlock_rdlock(the_rwlock) returns having acquired lock, and
         thread starts reading data
writer1  pthread_rwlock_wrlock(the_rwlock) hangs, as blocked by reader1/2
reader1  pthread_rwlock_unlock(the_rwlock) -> releases lock
reader1  pthread_rwlock_rwlock(the_rwlock) hangs, as pending writer
reader2  pthread_rwlock_unlock(the_rwlock) -> releases lock    
writer1  blocked pthread_rwlock_wrlock(the_rwlock) returns having acquired lock,
         and thread starts writing and/or reading data
writer1  pthread_rwlock_unlock(the_rwlock) -> releases lock    
reader1  blocked pthread_rwlock_rwlock(the_rwlock) returns having acquired lock,
         and thread starts reading data
...etc...