我正在使用 boost 的 ipc 库来保存复杂的对象,包括图像,在共享内存中,由多个进程使用。我们称这个对象为MyImage
。共享内存是一个循环缓冲区,保存了几个MyImage
一次对象。
在我的代码中,有两个(或更多)进程写入共享内存中的一个段,另一个进程从中读取。此流程按预期工作,但是在读取器进程完成或崩溃后,当它尝试再次打开共享内存中的同一对象时,它会卡住find
方法,而编写器进程仍然运行良好。
我试图了解哪种竞争条件可能导致此问题,但在我的代码或 boost 的文档中找不到任何解释。
这是我项目中问题的一个简单代码示例:
The Writer
过程:
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/ipc/message_queue.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/circular_buffer.hpp>
using namespace std;
namespace bip = boost::interprocess;
static const char *const PLACE_SHM_NAME = "PlaceInShm";
static const char *const OBJECT_SHM_NAME = "ObjectInShm";
static const char *const PUSH_POP_LOCK = "push_pop_image_lock";
static const int IMAGES_IN_BUFFER = 20;
static const int OBJECT_SIZE_IN_SHM = 91243520;
class MyImage;
typedef bip::managed_shared_memory::segment_manager SegmentManagerType;
typedef bip::allocator<void, SegmentManagerType> MyImageVoidAllocator;
typedef bip::deleter<MyImage, SegmentManagerType> MyImageDeleter;
typedef bip::shared_ptr<MyImage, MyImageVoidAllocator, MyImageDeleter> MyImageSharedPtr;
typedef bip::allocator<MyImageSharedPtr, bip::managed_shared_memory::segment_manager> MyImageShmemAllocator;
typedef boost::circular_buffer<MyImageSharedPtr, MyImageShmemAllocator> MyImageContainer;
MyImageSharedPtr GetMyImage() {
// some implementation
return nullptr;
}
int main(int argc, char *argv[]) {
MyImageContainer *my_image_data_container;
try {
bip::named_mutex open_lock{bip::open_or_create, OPEN_SHM_LOCK};
bip::managed_shared_memory image_segment = bip::managed_shared_memory(bip::open_or_create, PLACE_SHM_NAME, OBJECT_SIZE_IN_SHM);
my_image_data_container = image_segment.find_or_construct<MyImageContainer>(OBJECT_SHM_NAME)(IMAGES_IN_BUFFER, image_segment.get_segment_manager());
} catch (boost::interprocess::interprocess_exception &e) {
exit(1);
}
boost::interprocess::named_mutex my_image_mutex_ptr(boost::interprocess::open_or_create, PUSH_POP_LOCK);
while (true) {
MyImageSharedPtr img = GetMyImage();
my_image_mutex_ptr.lock();
my_image_data_container->push_back(img);
my_image_mutex_ptr.unlock();
usleep(1000);
}
}
The Reader
过程:
int main(int argc, char *argv[]) {
MyImageContainer *my_image_data_container;
try {
bip::named_mutex open_lock{bip::open_only, OPEN_SHM_LOCK};
bip::scoped_lock<bip::named_mutex> lock(open_lock, bip::try_to_lock);
bip::managed_shared_memory image_segment = bip::managed_shared_memory(bip::open_only, PLACE_SHM_NAME);
my_image_data_container = image_segment.find<MyImageContainer>(OBJECT_SHM_NAME).first;
} catch (boost::interprocess::interprocess_exception &e) {
exit(1);
}
boost::interprocess::named_mutex my_image_mutex_ptr(boost::interprocess::open_or_create, PUSH_POP_LOCK);
while (true) {
if (my_image_data_container->size() == 0) {
continue;
}
MyImage *img;
my_image_mutex_ptr.lock();
img = &(*my_image_data_container->at(0));
my_image_data_container->pop_front();
my_image_mutex_ptr.unlock();
// do stuff with img
usleep(1000);
}
}
重现该错误的流程:
- 运行两个进程
Writer
code.
- 运行其中一个进程
Reader
code.
- 杀死
Reader
过程。
- run the
Reader
再次处理。
第二次运行时,进程卡在队列中image_segment.find<MyImageContainer>(OBJECT_SHM_NAME).first;
而Writer
流程都很好。
值得一提的是,每个Writer
进程有唯一的id,并且只写入共享内存中的缓冲区int(IMAGES_IN_BUFFER / NUMBER_OF_WRITERS)
图像从索引开始作为他的 id。
例如,我有两个Writer
id 为 0 和 id 1 的 s,IMAGES_IN_BUFFER=20
, then Writer 0
将写入索引 0-9 和Writer 1
至 10-19。
我的一些调试过程:
- 我尝试在单独的线程中打开共享内存,使用
future
对象,并设置几秒钟的超时。但整个过程还是卡住了。
- 当我在卡住后终止该进程并重新运行它时,它永远不会再次成功,除非我从共享内存中删除该对象并重新运行所有进程,包括
Writer
s.
- 通常与一个人一起跑步时
Writer
我无法重现该错误,但我不能确定。
- 它不一致,这意味着我无法判断它何时会被卡住,何时不会被卡住。
- 也许共享内存中的对象以某种方式损坏了,而
Reader
进程崩溃,然后重新打开它时,它失败了。在这种情况下,我预计 boost 将引发异常而不是挂起。
- 当进程正常退出(退出代码为 0)时,也可能会发生这种情况。
等待听到一些关于可能导致流程卡住的原因的意见。
提前致谢!