Я думаю, что я предполагаю что-то из названия 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
Оказывается, 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)
— Если это ваш второй запуск, удалите любой случайный вывод с именем «имя_файла», если вы не хотите, чтобы второй запуск добавлялся к первому.
Других решений пока нет …