При форсировании библиотеки «межпроцессный» определяет named_mutex, работают ли эти named_mutexes правильно между различными процессами или только с потоками?

Я думаю, что я предполагаю что-то из названия boost::interprocess это неправда.
Документы повторяют, что named_mutex является глобальным Вот.

Я не могу заставить его работать, хотя. Две копии одного и того же исполняемого файла должны быть запущены одновременно, и я ожидаю, что именованный мьютекс в библиотеке с именем boost::interprocess может на самом деле БЛОК иногда. Это не так. Это также не предотвращает повреждение файла данных в коде ниже.

Вот некоторый код из документации Boost:

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>int main ()
{
using namespace boost::interprocess;
try{
struct file_remove
{
file_remove() { std::remove("file_name"); }
~file_remove(){ std::remove("file_name"); }
} file_remover;
struct mutex_remove
{
mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
} remover;

//Open or create the named mutex
named_mutex mutex(open_or_create, "fstream_named_mutex");

std::ofstream file("file_name");

for(int i = 0; i < 10; ++i){

//Do some operations...

//Write to file atomically
scoped_lock<named_mutex> lock(mutex);
file << "Process name, ";
file << "This is iteration #" << i;
file << std::endl;
}
}
catch(interprocess_exception &ex){
std::cout << ex.what() << std::endl;
return 1;
}
return 0;

Вот что я сделал с этим, чтобы доказать себе, что мьютекс что-то делал:

#include <windows.h>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
#include <iostream>
#include <cstdio>int main (int argc, char *argv[])
{
srand((unsigned) time(NULL));

using namespace boost::interprocess;
try{
/*
struct file_remove
{
file_remove() { std::remove("file_name"); }
~file_remove(){ std::remove("file_name"); }
} file_remover;
*/

struct mutex_remove
{
mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
} remover;

//Open or create the named mutex
named_mutex mutex(open_or_create, "fstream_named_mutex");

std::ofstream file("file_name");

for(int i = 0; i < 100; ++i){

//Do some operations...

//Write to file atomically
DWORD n1,n2;
n1 = GetTickCount();
scoped_lock<named_mutex> lock(mutex);
n2 = GetTickCount();
std::cout << "took " << (n2-n1) << " msec to acquire mutex";
int randomtime = rand()%10;
if (randomtime<1)
randomtime = 1;
Sleep(randomtime*100);
std::cout << " ... writing...\n";
if (argc>1)
file << argv[1];
else
file << "SOMETHING";
file << " This is iteration #" << i;
file << std::endl;
file.flush(); // added in case this explains the corruption, it does not.
}
}
catch(interprocess_exception &ex){
std::cout << "ERROR " << ex.what() << std::endl;
return 1;
}
return 0;
}

Консольный вывод:

took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...
took 0 msec to acquire mutex ... writing...

Также демо записывает в файл, в котором при запуске двух копий программы будут отсутствовать некоторые данные.

Я ожидаю, что если я удалю file_name и запустить две копии программы, я должен получить чередующиеся записи в file_name содержащий 100 строк из каждого экземпляра.

(Обратите внимание, что демонстрационный код явно не использует ofstream в режиме добавления вместо этого он просто перезаписывает файл при каждом запуске этой программы, поэтому, если мы хотим, чтобы демонстрационная программа показывала два процесса записи в файл, я знаю причину, по которой это не сработает, но то, что я ожидал для приведенного выше кода, чтобы быть реальной демонстрацией взаимного исключения, что это не так. Также звонки очень удобные и удачно названные ofstream::flush() метод мог быть включен, а не был.)

Использование Boost 1.53 в Visual C ++ 2008

2

Решение

Оказывается, Boost — замечательная библиотека, и примеры кода, вкрапленные в документацию, иногда могут быть испорчены. По крайней мере, один для boost::interprocess::named_mutex в документах не работает в системах Windows.

* Всегда удаление мьютекса как части демонстрационного кода приводит к тому, что мьютекс не функционирует. *

Это должно быть прокомментировано в демонстрационном коде по крайней мере. Он не соответствует «принципу наименьшего изумления», хотя я удивлялся, почему он там был, я думал, что он должен быть идиоматичным и необходимым, на самом деле идиотским и ненужным. Или, если это необходимо, это пример того, что Джоэл Спольски назвал бы неплотной абстракцией. Если мьютексы действительно являются точками файловой системы C:\ProgramData в Windows я точно не хочу об этом знать, или знаю, что от них останутся неприятности, которые сломают абстракцию, если я не обнаружу этот случай и не уберу его. (Конечно, пахнут как дружественная к posix семантика для мьютексов в Boost, заставили их использовать реализацию в стиле posix вместо прямого перехода к Win32 API и реализации простого мьютекса, не имеющего изменений в файловой системе.)

Вот рабочая демонстрация:

#include <windows.h>
#include <boost/interprocess/sync/interprocess_mutex.hpp>
#include <boost/lambda/lambda.hpp>
#include <iostream>
#include <iterator>
#include <algorithm>

#include <boost/interprocess/sync/scoped_lock.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <fstream>
#include <iostream>
#include <cstdio>
#include <windows.h>

int main (int argc, char *argv[])
{
srand((unsigned) time(NULL));

using namespace boost::interprocess;
try{
/*
// UNCOMMENT THIS IF YOU WANT TO MAKE THIS DEMO IMPOSSIBLE TO USE TO DEMO ANYTHING

struct file_remove
{
file_remove() { std::remove("file_name"); }
~file_remove(){ std::remove("file_name"); }
} file_remover;

// UNCOMMENT THIS IF YOU WANT TO BREAK THIS DEMO HORRIBLY:

struct mutex_remove
{
mutex_remove() { named_mutex::remove("fstream_named_mutex"); }
~mutex_remove(){ named_mutex::remove("fstream_named_mutex"); }
} remover;
*/

//Open or create the named mutex
named_mutex mutex(open_or_create, "fstream_named_mutex");

std::ofstream file("file_name", std::ios_base::app );
int randomtime = 0;
for(int i = 0; i < 100; ++i){

//Do some operations...

//Write to file atomically
DWORD n1,n2;
n1 = GetTickCount();

{
scoped_lock<named_mutex> lock(mutex);
n2 = GetTickCount();
std::cout << "took " << (n2-n1) << " msec to acquire mutex";

randomtime = rand()%10;
if (randomtime<1)
randomtime = 1;

std::cout << " ... writing...\n";
if (argc>1)
file << argv[1];
else
file << "SOMETHING";
file << "...";
Sleep(randomtime*100);
file << " This is iteration #" << i;
file << std::endl;
file.flush();
}
Sleep(randomtime*100); // let the other guy in.
}
}
catch(interprocess_exception &ex){
std::cout << "ERROR " << ex.what() << std::endl;
return 1;
}
return 0;
}

Я хотел бы критических замечаний и правок в этом ответе, чтобы у людей была рабочая демонстрация использования этого названного мьютекса.

Чтобы использовать демо:
— Постройте и запустите две копии. Передайте параметр, чтобы вы могли видеть, какой экземпляр записал какие строки (start myexename ABC а также start myexename DEF из командной строки в windows)
— Если это ваш второй запуск, удалите любой случайный вывод с именем «имя_файла», если вы не хотите, чтобы второй запуск добавлялся к первому.

введите описание изображения здесь

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]