C++ 通知boost interprocessing条件变量时未保持锁定会导致问题

C++ 通知boost interprocessing条件变量时未保持锁定会导致问题,c++,multithreading,concurrency,multiprocessing,boost-interprocess,C++,Multithreading,Concurrency,Multiprocessing,Boost Interprocess,更新21.02.2020:在通知时保持锁定实际上没有帮助。据我目前所知,等待进程在共享内存中留下的条件变量无效 所以我让这个应用程序使用boost进程间共享内存,并使用进程间条件变量同步对它的访问。 我在Windows上使用boost 1.62。我正在使用Microsoft Windows Build Tools 2015进行编译 发生的情况是,当我用Ctrl-C终止等待的进程时,通知进程在notify调用中卡住了 这里有一个演示程序,可以重现这个问题。您必须在没有任何参数的情况下运行可执行文件

更新21.02.2020:在通知时保持锁定实际上没有帮助。据我目前所知,等待进程在共享内存中留下的条件变量无效

所以我让这个应用程序使用boost进程间共享内存,并使用进程间条件变量同步对它的访问。 我在Windows上使用boost 1.62。我正在使用Microsoft Windows Build Tools 2015进行编译

发生的情况是,当我用Ctrl-C终止等待的进程时,通知进程在notify调用中卡住了

这里有一个演示程序,可以重现这个问题。您必须在没有任何参数的情况下运行可执行文件一次,以启动等待进程,并再次运行一些参数以启动通知进程。然后杀死第一个进程。有时,您会发现打印在“进入通知”时停止

#包括
#包括
#包括
#包括
#包括
#包括
结构共享数据
{
boost::进程间::进程间互斥体互斥体;
boost::进程间::进程间_条件;
bool test_bool=false;
};
int main(int argc,char*argv[])
{
使用名称空间boost::interprocess;
如果(argc==1){
结构shm_删除
{
shm_remove(){
共享内存对象::删除(“MySharedMemory”);
}
~shm_remove(){
共享内存对象::删除(“MySharedMemory”);
}
}去除剂;
共享内存对象shm(仅创建“MySharedMemory”,读写);
shm.truncate(sizeof(shared_data));
映射的_区域(shm,读_写);
void*addr=region.get_address();
共享_数据*数据=新(添加)共享_数据;
while(true){
作用域锁定锁(数据->互斥锁);
而(!数据->测试){
数据->条件.等待(锁定);
}
std::cout互斥);
数据->测试布尔=真;
}
STD::CUT< P>在调用<代码>通知< /代码>时不必持有锁,但在大多数情况下,您仍然应该这样做,因为否则一些线程(或在您的实例进程中)可能会错过通知。请考虑下面的场景:

  • 进程1获取锁并检查条件,但在调用
    条件之前被抢占。等待
  • 进程2调用
    条件。通知\u one
    -但没有要通知的进程
  • 你杀死了进程2
  • 现在进程1最终调用
    条件。等待
    -并永远等待
通过在调用notify之前获取锁,可以确保另一个进程已经调用了
wait
,因此不会错过通知。这也适用于
std::condition\u变量
,而不仅仅适用于进程间示例


在某些情况下,这可能不是一个问题(例如,因为您不会永远等待,而只等待有限的时间),但您应该非常小心。

我可以看到,在某些情况下,您必须在通知时持有锁。但是,在某些情况下,您不必持有锁,我认为我的示例就是其中之一。然而,我发现,在没有锁的情况下调用notify调用时阻止它是错误的行为(在上面的场景中).所以问题仍然存在,这是一个错误还是图书馆的一些限制?
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/interprocess/sync/interprocess_condition.hpp>

#include <iostream>

struct shared_data
{
   boost::interprocess::interprocess_mutex mutex;
   boost::interprocess::interprocess_condition condition;

   bool test_bool = false;
};


int main(int argc, char *argv[])
{
    using namespace boost::interprocess;

    if (argc == 1) {
        struct shm_remove
        {
            shm_remove() {
                shared_memory_object::remove("MySharedMemory");
            }
            ~shm_remove() {
                shared_memory_object::remove("MySharedMemory");
            }
        } remover;

        shared_memory_object shm(create_only, "MySharedMemory", read_write);

        shm.truncate(sizeof(shared_data));
        mapped_region region(shm, read_write);
        void* addr = region.get_address();
        shared_data* data = new (addr) shared_data;

        while (true) {
            scoped_lock<interprocess_mutex> lock(data->mutex);
            while (!data->test_bool) {
                data->condition.wait(lock);
            }
            std::cout << "test_bool became true" << std::endl;
            data->test_bool = false;
        }
    }
    else {
        shared_memory_object shm(open_only, "MySharedMemory", read_write);
        mapped_region region(shm, read_write);
        shared_data* data = static_cast<shared_data*>(region.get_address());
        while (true) {
            {
                scoped_lock<interprocess_mutex> lock(data->mutex);
                data->test_bool = true;
            }
            std::cout << "Entering notify" << std::endl;
            data->condition.notify_one();
            std::cout << "Exiting notify" << std::endl;
        }
    }
}