![]() |
![]() ![]() ![]() ![]() ![]() |
![]() |
Synchronization mechanismsBoost , The Boost C++ Libraries BoostBook Documentation Subset , Chapter 16. Boost.Interprocess
|
![]() | Important |
---|---|
< |
Повышаю. Interprocess предлагает следующие типы mutex:
#include <boost/interprocess/sync/interprocess_mutex.hpp>
interprocess_mutex
>: Нерекурсивный, анонимный мутекс, который может быть размещен в общей памяти или картированных файлах памяти.#include <boost/interprocess/sync/interprocess_recursive_mutex.hpp>
interprocess_recursive_mutex
>: Рекурсивный, анонимный мутекс, который может быть размещен в общей памяти или картированных файлах памяти.#include <boost/interprocess/sync/named_mutex.hpp>
named_mutex
>: Нерекурсивный, называется мутекс.#include <boost/interprocess/sync/named_recursive_mutex.hpp>
named_recursive_mutex
>: Рекурсивный, называется мутекс.Очень важно разблокировать мутекс после прочтения или записи данных. Это может быть трудно при работе с исключениями, поэтому обычно мутексы используются с ограниченным блокировкой, классом, который может гарантировать, что мутекс всегда будет разблокирован, даже когда происходит исключение. Чтобы использовать ограниченный замок, просто включите:
#include <boost/interprocess/sync/scoped_lock.hpp>
В основном, ограниченный замок вызываетразблокировкув своем деструкторе, и mutex всегда разблокируется, когда происходит исключение. Зафиксированный замок имеет много конструкторов для блокировки, try_lock, timed_lock mutex или вообще не блокировать его.
using namespace boost::interprocess; //Let's create any mutex type: MutexType mutex; { //This will lock the mutex scoped_lock<MutexType> lock(mutex); //Some code //The mutex will be unlocked here } { //This will try_lock the mutex scoped_lock<MutexType> lock(mutex, try_to_lock); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked } { boost::posix_time::ptime abs_time = ... //This will timed_lock the mutex scoped_lock<MutexType> lock(mutex, abs_time); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked }
Для получения дополнительной информации проверьте<scoped_lock's
reference
>.
![]() | Important |
---|---|
< |
Представьте, что два процесса должны записывать следы в циклический буфер, встроенный в общую память. Каждый процесс должен получить эксклюзивный доступ к циклическому буферу, записать след и продолжить.
Чтобы защитить циклический буфер, мы можем хранить общий процесс mutex в циклическом буфере. Каждый процесс блокирует mutex перед записью данных и записывает флаг, когда заканчивается запись следов (заголовок 177):
#include <boost/interprocess/sync/interprocess_mutex.hpp> struct shared_memory_log { enum { NumItems = 100 }; enum { LineSize = 100 }; shared_memory_log() : current_line(0) , end_a(false) , end_b(false) {} //Mutex to protect access to the queue boost::interprocess::interprocess_mutex mutex; //Items to fill char items[NumItems][LineSize]; int current_line; bool end_a; bool end_b; };
Это основной процесс процесса. Создает общую память, строит циклический буфер и начинает записывать следы:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include "doc_anonymous_mutex_shared_data.hpp" #include <iostream> #include <cstdio> using namespace boost::interprocess; int main () { try{ //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MySharedMemory"); } ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); //Set size shm.truncate(sizeof(shared_memory_log)); //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Construct the shared structure in memory shared_memory_log * data = new (addr) shared_memory_log; //Write some logs for(int i = 0; i < shared_memory_log::NumItems; ++i){ //Lock the mutex scoped_lock<interprocess_mutex> lock(data->mutex); std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] ,"%s_%d", "process_a", i); if(i == (shared_memory_log::NumItems-1)) data->end_a = true; //Mutex is released here } //Wait until the other process ends while(1){ scoped_lock<interprocess_mutex> lock(data->mutex); if(data->end_b) break; } } catch(interprocess_exception &ex){ std::cout << ex.what() << std::endl; return 1; } return 0; }
Второй процесс открывает общую память, получает доступ к циклическому буферу и начинает запись следов:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include "doc_anonymous_mutex_shared_data.hpp" #include <iostream> #include <cstdio> using namespace boost::interprocess; int main () { //Remove shared memory on destruction struct shm_remove { ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } } remover; //Open the shared memory object. shared_memory_object shm (open_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Construct the shared structure in memory shared_memory_log * data = static_cast<shared_memory_log*>(addr); //Write some logs for(int i = 0; i < 100; ++i){ //Lock the mutex scoped_lock<interprocess_mutex> lock(data->mutex); std::sprintf(data->items[(data->current_line++) % shared_memory_log::NumItems] ,"%s_%d", "process_a", i); if(i == (shared_memory_log::NumItems-1)) data->end_b = true; //Mutex is released here } //Wait until the other process ends while(1){ scoped_lock<interprocess_mutex> lock(data->mutex); if(data->end_a) break; } return 0; }
Как мы видим, мутекс полезен для защиты данных, но не для уведомления события о другом процессе. Для этого нам нужна переменная состояния, как мы увидим в следующем разделе.
Теперь представьте, что два процесса хотят написать след к файлу. Сначала они пишут свое имя, а затем пишут сообщение. Поскольку операционная система может прерывать процесс в любой момент, мы можем смешивать части сообщений обоих процессов, поэтому нам нужен способ записи всего сообщения в файл атомарно. Для этого мы можем использовать мутекс, чтобы каждый процесс блокировал мутекс перед написанием:
#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; }
В предыдущем примере мутекс используется дляблокировки, но мы не можем использовать его дляэффективного ожидания, пока не будет выполнено условие для продолжения. Переменная состояния может делать две вещи:
Ожидание переменной состояния всегда связано с мутексом. Мутекс должен быть заблокирован, прежде чем ждать условия. При ожидании переменной состояния нить разблокирует мутекс и ждетатомарно.
Когда поток возвращается из функции ожидания (например, из-за сигнала или тайм-аута), объект mutex снова блокируется.
Повышаю. Interprocess предлагает следующие типы условий:
#include <boost/interprocess/sync/interprocess_condition.hpp>
interprocess_condition
>: Анонимная переменная состояния, которая может быть размещена в общей памяти или картированных файлах памяти для использования с<boost::interprocess::interprocess_mutex
>.#include <boost/interprocess/sync/interprocess_condition_any.hpp>
interprocess_condition_any
>: Анонимная переменная состояния, которая может быть размещена в общей памяти или картированных файлах памяти для использования с любым типом блокировки.#include <boost/interprocess/sync/named_condition.hpp>
named_condition
>: Названная переменная состояния, которую следует использовать<named_mutex
>.#include <boost/interprocess/sync/named_condition_any.hpp>
named_condition
>: Названная переменная состояния, которая будет использоваться с любым типом замка.Названные условия похожи на анонимные, но они используются в сочетании с названными мутексами. Несколько раз мы не хотим хранить объекты синхронизации с синхронизированными данными:
Представьте себе процесс, который записывает след к простому буферу общей памяти, который другой процесс печатает один за другим. Первый процесс записывает след и ждет, пока другой процесс не распечатает данные. Для достижения этой цели мы можем использовать две переменные состояния: первая используется для блокировки отправителя до тех пор, пока второй процесс не распечатает сообщение, а вторая — для блокировки приемника до тех пор, пока буфер не отследит печать.
Буфер трассировки общей памяти (doc_anonymous_condition_shared_data.hpp):
#include <boost/interprocess/sync/interprocess_mutex.hpp> #include <boost/interprocess/sync/interprocess_condition.hpp> struct trace_queue { enum { LineSize = 100 }; trace_queue() : message_in(false) {} //Mutex to protect access to the queue boost::interprocess::interprocess_mutex mutex; //Condition to wait when the queue is empty boost::interprocess::interprocess_condition cond_empty; //Condition to wait when the queue is full boost::interprocess::interprocess_condition cond_full; //Items to fill char items[LineSize]; //Is there any message bool message_in; };
Это основной процесс процесса. Создает общую память, размещает там буфер и начинает писать сообщения один за другим, пока не напишет «последнее сообщение», чтобы указать, что больше нет сообщений для печати:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <iostream> #include <cstdio> #include "doc_anonymous_condition_shared_data.hpp" using namespace boost::interprocess; int main () { //Erase previous shared memory and schedule erasure on exit struct shm_remove { shm_remove() { shared_memory_object::remove("MySharedMemory"); } ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); try{ //Set size shm.truncate(sizeof(trace_queue)); //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Construct the shared structure in memory trace_queue * data = new (addr) trace_queue; const int NumMsg = 100; for(int i = 0; i < NumMsg; ++i){ scoped_lock<interprocess_mutex> lock(data->mutex); if(data->message_in){ data->cond_full.wait(lock); } if(i == (NumMsg-1)) std::sprintf(data->items, "%s", "last message"); else std::sprintf(data->items, "%s_%d", "my_trace", i); //Notify to the other process that there is a message data->cond_empty.notify_one(); //Mark message buffer as full data->message_in = true; } } catch(interprocess_exception &ex){ std::cout << ex.what() << std::endl; return 1; } return 0; }
Второй процесс открывает общую память и печатает каждое сообщение, пока не будет получено сообщение «последнее сообщение»:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> #include <iostream> #include <cstring> #include "doc_anonymous_condition_shared_data.hpp" using namespace boost::interprocess; int main () { //Create a shared memory object. shared_memory_object shm (open_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); try{ //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Obtain a pointer to the shared structure trace_queue * data = static_cast<trace_queue*>(addr); //Print messages until the other process marks the end bool end_loop = false; do{ scoped_lock<interprocess_mutex> lock(data->mutex); if(!data->message_in){ data->cond_empty.wait(lock); } if(std::strcmp(data->items, "last message") == 0){ end_loop = true; } else{ //Print the message std::cout << data->items << std::endl; //Notify the other process that the buffer is empty data->message_in = false; data->cond_full.notify_one(); } } while(!end_loop); } catch(interprocess_exception &ex){ std::cout << ex.what() << std::endl; return 1; } return 0; }
С переменными состояния процесс может блокироваться, если он не может продолжать работу, и когда условия для продолжения выполняются, другой процесс может разбудить его.
Семафор - это механизм синхронизации между процессами, основанный на внутреннем счете, который предлагает две основные операции:
Если начальное количество семафоров инициализировано до 1, операцияОжиданиеэквивалентна блокировке мутекса, аПостэквивалентна разблокировке мутекса. Этот тип семафора известен какбинарный семафор.
Хотя семафоры могут использоваться как мутексы, они имеют уникальную особенность: в отличие от мутексов, операцияPostне должна выполняться тем же потоком/процессом, который выполнял операциюWait.
Повышаю. Interprocess предлагает следующие типы семафоров:
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
interprocess_semaphore
>: Анонимный семафор, который может быть помещен в общую память или картированные файлы памяти.#include <boost/interprocess/sync/named_semaphore.hpp>
named_semaphore
>: По имени Семафор.Мы реализуем целочисленный массив в общей памяти, который будет использоваться для передачи данных из одного процесса в другой. Первый процесс будет записывать несколько целых чисел в массив, и процесс будет блокироваться, если массив заполнен.
Второй процесс будет копировать переданные данные в собственный буфер, блокируя, если в буфере нет новых данных.
Это общий массив целых чисел (doc_anonymous_semaphore_shared_data.hpp):
#include <boost/interprocess/sync/interprocess_semaphore.hpp> struct shared_memory_buffer { enum { NumItems = 10 }; shared_memory_buffer() : mutex(1), nempty(NumItems), nstored(0) {} //Semaphores to protect and synchronize access boost::interprocess::interprocess_semaphore mutex, nempty, nstored; //Items to fill int items[NumItems]; };
Это основной процесс процесса. Создает общую память, помещает туда целочисленный массив и начинает целочисленные числа один за другим, блокируя, если массив заполнен:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <iostream> #include "doc_anonymous_semaphore_shared_data.hpp" using namespace boost::interprocess; int main () { //Remove shared memory on construction and destruction struct shm_remove { shm_remove() { shared_memory_object::remove("MySharedMemory"); } ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } } remover; //Create a shared memory object. shared_memory_object shm (create_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); //Set size shm.truncate(sizeof(shared_memory_buffer)); //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Construct the shared structure in memory shared_memory_buffer * data = new (addr) shared_memory_buffer; const int NumMsg = 100; //Insert data in the array for(int i = 0; i < NumMsg; ++i){ data->nempty.wait(); data->mutex.wait(); data->items[i % shared_memory_buffer::NumItems] = i; data->mutex.post(); data->nstored.post(); } return 0; }
Второй процесс открывает общую память и копирует полученные целые числа в собственный буфер:
#include <boost/interprocess/shared_memory_object.hpp> #include <boost/interprocess/mapped_region.hpp> #include <iostream> #include "doc_anonymous_semaphore_shared_data.hpp" using namespace boost::interprocess; int main () { //Remove shared memory on destruction struct shm_remove { ~shm_remove(){ shared_memory_object::remove("MySharedMemory"); } } remover; //Create a shared memory object. shared_memory_object shm (open_only //only create ,"MySharedMemory" //name ,read_write //read-write mode ); //Map the whole shared memory in this process mapped_region region (shm //What to map ,read_write //Map it as read-write ); //Get the address of the mapped region void * addr = region.get_address(); //Obtain the shared structure shared_memory_buffer * data = static_cast<shared_memory_buffer*>(addr); const int NumMsg = 100; int extracted_data [NumMsg]; //Extract the data for(int i = 0; i < NumMsg; ++i){ data->nstored.wait(); data->mutex.wait(); extracted_data[i] = data->items[i % shared_memory_buffer::NumItems]; data->mutex.post(); data->nempty.post(); } return 0; }
Такая же связь между процессами может быть достигнута с переменными состояния и мутексами, но для нескольких моделей синхронизации семафор более эффективен, чем комбинация мутекс/состояние.
Совместимые и модернизируемые mutex - это специальные типы mutex, которые предлагают больше возможностей блокировки, чем обычные mutex. Иногда мы можем различатьчтениеданных иизменениеданных. Если только некоторые потоки нуждаются в изменении данных, и для защиты данных от одновременного доступа используется простой mutex, параллелизм довольно ограничен: два потока, которые только читают данные, будут сериализованы вместо того, чтобы выполняться одновременно.
Если мы разрешаем одновременный доступ к потокам, которые просто читают данные, но мы избегаем одновременного доступа между потоками, которые читают и изменяют, или между потоками, которые изменяют, мы можем увеличить производительность. Это особенно верно в приложениях, где чтение данных более распространено, чем модификация данных, и для выполнения кода синхронизированного чтения данных требуется некоторое время. С шарабельным мутексом мы можем приобрести 2 типа замка:
С обновленным mutex мы можем приобрести предыдущие замки плюс новый обновленный замок:
Подводя итог:
Table 16.5. Locking Possibilities for a Sharable Mutex
Если нить приобрела... |
Другие потоки могут приобретать... |
---|---|
Шарабельный замок | много сепарабельных замков |
Эксклюзивный замок | Замков нет |
Table 16.6. Locking Possibilities for an Upgradable Mutex
Если нить приобрела... |
Другие потоки могут приобретать... |
---|---|
Шарабельный замок | много съемных замков и 1 модернизируемый замок |
Модифицируемый замок | много сепарабельных замков |
Эксклюзивный замок | Замков нет |
Шарабельный мутекс не имеет возможности изменить приобретенный замок на другой замок атомарно.
С другой стороны, для модифицируемого мутекса нить, которая приобрела замок, может попытаться получить другой тип замка атомарно. Все переходы блокировки не гарантируют успеха. Даже если переход гарантирован для успеха, некоторые переходы будут блокировать нить, ожидая, пока другие нити не выпустят шарнирные замки.Атомноозначает, что ни один другой поток не будет приобретать Модифицируемый или Исключительный замок в переходе, поэтому данные гарантированно останутся неизменными:
Table 16.7. Transition Possibilities for an Upgradable Mutex
Если нить приобрела... |
Он может атомарно освободить предыдущий замок и... |
---|---|
Шарабельный замок | попытаться получить (не гарантировано) немедленно Исключительный замок, если ни одна другая нить не имеет эксклюзивного или восходящего замка |
Шарабельный замок | попытаться получить (не гарантировано) немедленно Модифицируемый замок, если ни одна другая нить не имеет эксклюзивного или восходящего замка . |
Модифицируемый замок | получить Исключительный замок, когда все сепаративные замки будут выпущены |
Модифицируемый замок | Немедленно получить замок Шарабле |
Эксклюзивный замок | Получить Модифицируемый замок немедленно |
Эксклюзивный замок | Немедленно получить замок Шарабле |
Как мы видим, модернизируемый mutex является мощной утилитой синхронизации, которая может улучшить параллель. Однако, если большую часть времени нам приходится модифицировать данные, или синхронизированный раздел кода очень короткий, более эффективно использовать простой мутекс, поскольку он имеет меньше накладных расходов. Модифицируемый замок сияет, когда синхронизированный раздел кода больше, и читателей больше, чем модификаторов.
Все модифицируемые типы мутексовBoost.Interprocessосуществляют следующие операции:
Эффекты:Вызывающая нить пытается получить исключительное право собственности на mutex, и если другая нить имеет какое-либо право собственности на mutex (исключительное или другое), она ждет, пока она не сможет получить право собственности.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести эксклюзивное право собственности на мутекс, не дожидаясь. Если ни одна другая нить не имеет права собственности на mutex (эксклюзивную или другую), это достигает успеха.
Возвращение:Если он может приобрести эксклюзивное право собственности сразу же возвращается. Если придется подождать, верните ложную информацию.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести исключительное право собственности на mutex, ожидая, если это необходимо, пока ни одна другая нить не получит право собственности на mutex (исключительное или другое) или не будет достигнуто время abs_.
Возвращение:Если приобретается исключительное право собственности, возвращается правда. В противном случае возврат ложный.
Броски:межпроцессное_исключениепо ошибке.
Предварительное условие:Нить должна иметь исключительное право собственности на mutex.
Эффекты:Призывной поток освобождает исключительное право собственности на mutex.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Эффекты:Вызывающая нить пытается получить съемное право собственности на mutex, и если другая нить имеет исключительное право собственности на mutex, ждет, пока она сможет получить право собственности.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести съедобное владение мутексом, не дожидаясь. Если ни одна другая нить не имеет исключительного права собственности на mutex, это удается.
Возвращение:Если он может приобрести сельскохозяйственную собственность, немедленно возвращается правда. Если придется подождать, верните ложную информацию.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести съемное право собственности на mutex, ожидая, если это необходимо, пока не будет достигнута эксклюзивная собственность на mutex или abs_time.
Возвращение:Если приобретается сельскохозяйственная собственность, возвращается правда. В противном случае возврат ложный.
Броски:межпроцессное_исключениепо ошибке.
Предварительное условие:Нить должна иметь съемное право собственности на мутекс.
Эффекты:Вызывающая нить освобождает съемное владение мутексом.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Эффекты:Вызывающая нить пытается получить модернизируемое право собственности на mutex, и если другая нить имеет эксклюзивное или модернизируемое право собственности на mutex, ждет, пока она не сможет получить право собственности.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести обновляемое владение мутексом, не дожидаясь. Если ни одна другая нить не имеет эксклюзивного или модернизируемого права собственности на mutex, это удается.
Возвращение:Если он может приобрести сельскохозяйственную собственность, немедленно возвращается правда. Если придется подождать, верните ложную информацию.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающая нить пытается приобрести модернизируемое право собственности на mutex, ожидая, если это необходимо, пока ни одна другая нить не получит эксклюзивное право собственности на mutex или abs_time.
Возвращение:Если приобретается обновляемая собственность, возвращается правда. В противном случае возврат ложный.
Броски:межпроцессное_исключениепо ошибке.
Предварительное условие:Нить должна иметь обновляемое владение mutex.
Эффекты:Вызывающая нить освобождает обновляемое владение mutex.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь исключительное право собственности на mutex.
Эффекты:Нить атомарно освобождает исключительную собственность и приобретает модернизируемую собственность. Эта операция не блокируется.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь исключительное право собственности на mutex.
Эффекты:Нить атомарно освобождает эксклюзивную собственность и приобретает сельскохозяйственную собственность. Эта операция не блокируется.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь обновляемое владение mutex.
Эффекты:Нить атомарно высвобождает модернизируемое владение и приобретает шаровое владение. Эта операция не блокируется.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь обновляемое владение mutex.
Эффекты:Нить атомарно высвобождает модернизируемую собственность и приобретает исключительную собственность. Эта операция будет блокироваться до тех пор, пока все нити с шаровой собственностью не выпустят ее.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь обновляемое владение mutex.
Эффекты:Нить атомарно высвобождает модернизируемую собственность и пытается приобрести исключительную собственность. Эта операция потерпит неудачу, если есть нити с съемным владением, но она сохранит обновляемое владение.
Возвращение:Если приобретается исключительное право собственности, возвращается правда. В противном случае возврат ложный.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь обновляемое владение mutex.
Эффекты:Нить атомарно освобождает обновляемую собственность и пытается приобрести эксклюзивную собственность, ожидая при необходимости до abs_time. Эта операция потерпит неудачу, если есть нити с шариатным владением или тайм-аутом, но она будет поддерживать модернизируемое владение.
Возвращение:Если приобретается исключительное право собственности, возвращается правда. В противном случае возврат ложный.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь съемное право собственности на мутекс.
Эффекты:Нить атомарно освобождает сельскохозяйственную собственность и пытается приобрести исключительную собственность. Эта операция потерпит неудачу, если есть нити с съемным или модернизируемым владением, но она сохранит съемное владение.
Возвращение:Если приобретается исключительное право собственности, возвращается правда. В противном случае возврат ложный.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Предварительное условие:Нить должна иметь съемное право собственности на мутекс.
Эффекты:Нить атомарно освобождает сельскохозяйственную собственность и пытается приобрести модернизируемую собственность. Эта операция потерпит неудачу, если есть нити с съемным или модернизируемым владением, но она сохранит съемное владение.
Возвращение:Если приобретается обновляемая собственность, возвращается правда. В противном случае возврат ложный.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
![]() | Important |
---|---|
< |
Повышаю. Interprocess предлагает следующие типы mutex:
#include <boost/interprocess/sync/interprocess_sharable_mutex.hpp>
interprocess_sharable_mutex
>: Нерекурсивный, анонимный мутекс, который может быть размещен в общей памяти или картированных файлах памяти.#include <boost/interprocess/sync/named_sharable_mutex.hpp>
named_sharable_mutex
>: Нерекурсивный, называется шарабельный мутекс.Повышаю. Interprocess предлагает следующие типы mutex:
#include <boost/interprocess/sync/interprocess_upgradable_mutex.hpp>
interprocess_upgradable_mutex
>: Нерекурсивный, анонимный обновленный mutex, который может быть размещен в общей памяти или картированных файлах памяти.#include <boost/interprocess/sync/named_upgradable_mutex.hpp>
named_upgradable_mutex
>: Нерекурсивный, названный модернизируемым мутексом.Как и в случае с простыми мутексами, важно освободить приобретенный замок даже при наличии исключений.Boost.Interprocessmutexes лучше всего использовать с утилитой<scoped_lock
>, и этот класс предлагает только эксклюзивную блокировку.
Поскольку у нас есть съемная блокировка и модернизируемая блокировка с модернизируемыми мутексами, у нас есть две новые утилиты:<sharable_lock
>и<upgradable_lock
>. Оба класса похожи на<scoped_lock
>, но<sharable_lock
>приобретает съемный замок в конструкторе и<upgradable_lock
>приобретает модернизируемый замок в конструкторе.
Эти две утилиты можно использовать с любым объектом синхронизации, который предлагает необходимые операции. Например, тип mutex, определяемый пользователем, без улучшаемых функций блокировки, может использоваться<sharable_lock
>, если объект синхронизации предлагаетlock_sharable()иunlock_sharable()операции:
#include <boost/interprocess/sync/sharable_lock.hpp>
#include <boost/interprocess/sync/upgradable_lock.hpp>
<sharable_lock
>вызываетunlock_sharable()в своем деструкторе, и<upgradable_lock
>вызываетunlock_upgradable()в своем деструкторе, поэтому обновленный mutex всегда разблокируется, когда происходит исключение.
using namespace boost::interprocess; SharableOrUpgradableMutex sh_or_up_mutex; { //This will call lock_sharable() sharable_lock<SharableOrUpgradableMutex> lock(sh_or_up_mutex); //Some code //The mutex will be unlocked here } { //This won't lock the mutex() sharable_lock<SharableOrUpgradableMutex> lock(sh_or_up_mutex, defer_lock); //Lock it on demand. This will call lock_sharable() lock.lock(); //Some code //The mutex will be unlocked here } { //This will call try_lock_sharable() sharable_lock<SharableOrUpgradableMutex> lock(sh_or_up_mutex, try_to_lock); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked } { boost::posix_time::ptime abs_time = ... //This will call timed_lock_sharable() scoped_lock<SharableOrUpgradableMutex> lock(sh_or_up_mutex, abs_time); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked } UpgradableMutex up_mutex; { //This will call lock_upgradable() upgradable_lock<UpgradableMutex> lock(up_mutex); //Some code //The mutex will be unlocked here } { //This won't lock the mutex() upgradable_lock<UpgradableMutex> lock(up_mutex, defer_lock); //Lock it on demand. This will call lock_upgradable() lock.lock(); //Some code //The mutex will be unlocked here } { //This will call try_lock_upgradable() upgradable_lock<UpgradableMutex> lock(up_mutex, try_to_lock); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked } { boost::posix_time::ptime abs_time = ... //This will call timed_lock_upgradable() scoped_lock<UpgradableMutex> lock(up_mutex, abs_time); //Check if the mutex has been successfully locked if(lock){ //Some code } //If the mutex was locked it will be unlocked }
<upgradable_lock
>и<sharable_lock
>предлагают больше функций и операций, см. их ссылку для получения дополнительной информации.
![]() | Important |
---|---|
< |
Охваченные замки и аналогичные утилиты предлагают простые возможности управления ресурсами, но с продвинутыми типами mutex, такими как модернизируемые mutexes, существуют операции, при которых приобретенный тип замка высвобождается, а другой тип замка приобретается атомарно. Это достигается за счет таких операций, как<unlock_and_lock_sharable()
>.
Этими операциями можно управлять более эффективно, используя операции передачи блокировки. Операции переноса блокировок явно указывают на то, что мутекс, принадлежащий блокировщику, передается другому блокировщику, выполняющему атомную разблокировку плюс операции блокировки.
Представьте, что поток изменяет некоторые данные в начале, но после этого он должен просто прочитать их в течение длительного времени. Код может приобретать эксклюзивный замок, изменять данные и атомарно освобождать эксклюзивный замок и приобретать шарнирный замок. С помощью этой последовательности мы гарантируем, что ни один другой поток не сможет изменить данные в переходе, и что больше читателей смогут получить доступный замок, увеличивая параллель. Без операций передачи блокировки это было бы закодировано так:
using boost::interprocess; interprocess_upgradable_mutex mutex; //Acquire exclusive lock mutex.lock(); //Modify data //Atomically release exclusive lock and acquire sharable lock. //More threads can acquire the sharable lock and read the data. mutex.unlock_and_lock_sharable(); //Read data //Explicit unlocking mutex.unlock_sharable();
Это может быть просто, но при наличии исключений сложно узнать, какой тип блокировки был у мутекса, когда исключение было брошено, и какую функцию мы должны назвать, чтобы разблокировать его:
try{ //Mutex operations } catch(...){ //What should we call? "unlock()" or "unlock_sharable()" //Is the mutex locked? }
Мы можем использоватьпередачу блокировкидля упрощения всего этого управления:
using boost::interprocess; interprocess_upgradable_mutex mutex; //Acquire exclusive lock scoped_lock s_lock(mutex); //Modify data //Atomically release exclusive lock and acquire sharable lock. //More threads can acquire the sharable lock and read the data. sharable_lock(move(s_lock)); //Read data //The lock is automatically unlocked calling the appropriate unlock //function even in the presence of exceptions. //If the mutex was not locked, no function is called.
Как мы видим, даже если в любой момент будет сделано исключение, mutex будет автоматически разблокирован, вызывая соответствующий метод<unlock()
>или<unlock_sharable()
>.
Существует множество операций передачи блокировок, которые мы можем классифицировать в соответствии с операциями, представленными в обновленных операциях mutex:
Трансферы в<scoped_lock
>гарантированно будут успешными только с<upgradable_lock
>и только в том случае, если будет запрошена операция блокировки, из-за того, что эта операция должна ждать, пока все шарнирные замки не будут выпущены. Пользователь также может использовать «попробовать» или «своевременную» передачу, чтобы избежать бесконечной блокировки, но успех не гарантирован.
Конверсия из<sharable_lock
>никогда не гарантируется и, таким образом, допускается только пробная операция:
//Conversions to scoped_lock { upgradable_lock<Mutex> u_lock(mut); //This calls unlock_upgradable_and_lock() scoped_lock<Mutex> e_lock(move(u_lock)); } { upgradable_lock<Mutex> u_lock(mut); //This calls try_unlock_upgradable_and_lock() scoped_lock<Mutex> e_lock(move(u_lock, try_to_lock)); } { boost::posix_time::ptime t = test::delay(100); upgradable_lock<Mutex> u_lock(mut); //This calls timed_unlock_upgradable_and_lock() scoped_lock<Mutex> e_lock(move(u_lock)); } { sharable_lock<Mutex> s_lock(mut); //This calls try_unlock_sharable_and_lock() scoped_lock<Mutex> e_lock(move(s_lock, try_to_lock)); }
![]() | Important |
---|---|
< |
Переход на<upgradable_lock
>гарантированно будет успешным только с<scoped_lock
>, поскольку ограниченное блокирование является более ограничительным, чем модернизируемое блокирование. Эта операция также не блокируется.
Передача<sharable_lock
>не гарантируется и допускается только операция «попробовать»:
//Conversions to upgradable { sharable_lock<Mutex> s_lock(mut); //This calls try_unlock_sharable_and_lock_upgradable() upgradable_lock<Mutex> u_lock(move(s_lock, try_to_lock)); } { scoped_lock<Mutex> e_lock(mut); //This calls unlock_and_lock_upgradable() upgradable_lock<Mutex> u_lock(move(e_lock)); }
Все переводы на<sharable_lock
>гарантированно будут успешными, поскольку и<upgradable_lock
>и<scoped_lock
>являются более ограничительными, чем<sharable_lock
>. Эти операции также не блокируют:
//Conversions to sharable_lock { upgradable_lock<Mutex> u_lock(mut); //This calls unlock_upgradable_and_lock_sharable() sharable_lock<Mutex> s_lock(move(u_lock)); } { scoped_lock<Mutex> e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock<Mutex> s_lock(move(e_lock)); }
В предыдущих примерах мутекс, используемый в операции переноса, был ранее заблокирован:
Mutex mut; //This calls mut.lock() scoped_lock<Mutex> e_lock(mut); //This calls unlock_and_lock_sharable() sharable_lock<Mutex> s_lock(move(e_lock)); }
Но можно выполнить передачу с незапертым источником из-за явной разблокировки, попытки, времени или конструктора<defer_lock
>:
//These operations can leave the mutex unlocked! { //Try might fail scoped_lock<Mutex> e_lock(mut, try_to_lock); sharable_lock<Mutex> s_lock(move(e_lock)); } { //Timed operation might fail scoped_lock<Mutex> e_lock(mut, time); sharable_lock<Mutex> s_lock(move(e_lock)); } { //Avoid mutex locking scoped_lock<Mutex> e_lock(mut, defer_lock); sharable_lock<Mutex> s_lock(move(e_lock)); } { //Explicitly call unlock scoped_lock<Mutex> e_lock(mut); e_lock.unlock(); //Mutex was explicitly unlocked sharable_lock<Mutex> s_lock(move(e_lock)); }
Если источник мутекса не был заблокирован:
unlock_xxx_and_lock_xxx
>.{ scoped_lock<Mutex> e_lock(mut, defer_lock); sharable_lock<Mutex> s_lock(move(e_lock)); //Assertions assert(e_lock.mutex() == 0); assert(s_lock.mutex() != 0); assert(e_lock.owns() == false); }
При выполнении передачи блокировки операция может выйти из строя:
В первом случае право собственности на mutex не передается, и деструктор замка источника разблокирует mutex:
{ scoped_lock<Mutex> e_lock(mut, defer_lock); //This operations throws because //"unlock_and_lock_sharable()" throws!!! sharable_lock<Mutex> s_lock(move(e_lock)); //Some code ... //e_lock's destructor will call "unlock()" }
Во втором случае, если внутренняя «пробная» или «временная» операция выходит из строя (возвращает «ложную»), то право собственности на mutexнепередается, блокировка источника не изменяется, и состояние замка цели будет таким же, как и по умолчанию:
{ sharable_lock<Mutex> s_lock(mut); //Internal "try_unlock_sharable_and_lock_upgradable()" returns false upgradable_lock<Mutex> u_lock(move(s_lock, try_to_lock)); assert(s_lock.mutex() == &mut); assert(s_lock.owns() == true); assert(u_lock.mutex() == 0); assert(u_lock.owns() == false); //u_lock's destructor does nothing //s_lock's destructor calls "unlock()" }
Файловый замок представляет собой механизм синхронизации между процессами для защиты одновременных записей и чтения файлов с использованием mutex, встроенногов файл. Этотвстроенный mutexимеет шарнирные и эксклюзивные возможности блокировки. При блокировке файлов существующий файл может использоваться в качестве мутекса без необходимости создания дополнительных объектов синхронизации для управления одновременными считываниями или записью файлов.
Вообще говоря, мы можем иметь две возможности блокировки файлов:
Boost.Interprocessреализуетконсультативную блокировкупо причинам переносимости. Это означает, что каждый процесс доступа к файлу одновременно должен сотрудничать с использованием файловых замков для синхронизации доступа.
В некоторых системах блокировка файлов может быть еще более усовершенствована, что приводит кблокировке записи, где пользователь может указать байтовый диапазонв файле, где применяется блокировка. Это позволяет одновременно записывать доступ несколькими процессами, если им нужен доступ к другому диапазону байтов в файле.Boost.Interprocessдействительнонепредлагает блокировку записи на данный момент, но может предложить ее в будущем. Чтобы использовать блокировку файлов, просто включите:
#include <boost/interprocess/sync/file_lock.hpp>
Запирание файлов - это класс, который имеет.срок службы. Это означает, что если процесс с блокировкой файлов заканчивается или ломается, операционная система автоматически разблокирует его. Эта функция очень полезна в некоторых ситуациях, когда мы хотим обеспечить автоматическую разблокировку даже при сбое процесса и не оставлять заблокированные ресурсы в системе. Файловый замок строится с использованием имени файла в качестве аргумента:
#include <boost/interprocess/sync/file_lock.hpp> int main() { //This throws if the file does not exist or it can't //open it with read-write access! boost::interprocess::file_lock flock("my_file"); return 0; }
Запирание файлов имеет нормальные операции mutex плюс возможности блокировки. Это означает, что у нас может быть несколько читателей, держащих съедобный замок, и писатели, держащие эксклюзивный замок, ждут, пока читатели не закончат свою работу.
Однако блокировка файловнеподдерживает обновление блокировки или продвижение или демонтаж (перенос блокировок), поэтому она более ограничена, чем обновление блокировки. Это и есть операции:
Эффекты:Вызывающий поток пытается получить эксклюзивное право собственности на блокировку файлов, и если другой поток имеет эксклюзивное или совместное право собственности на mutex, он ждет, пока он не сможет получить право собственности.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Поток вызова пытается приобрести эксклюзивное право собственности на блокировку файлов без ожидания. Если ни один другой поток не имеет эксклюзивного или общего права собственности на блокировку файлов, это удается.
Возвращение:Если он может приобрести эксклюзивное право собственности сразу же возвращается. Если придется подождать, верните ложную информацию.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающий поток пытается приобрести эксклюзивное право собственности на блокировку файлов, ожидая, если это необходимо, пока другой поток не получит эксклюзивное или совместное право собственности на блокировку файлов или время abs_.
Возвращение:Если приобретается исключительное право собственности, возвращается правда. В противном случае возврат ложный.
Броски:межпроцессное_исключениепо ошибке.
Предварительное условие:Нить должна иметь исключительное право собственности на блокировку файлов.
Эффекты:Позывной поток освобождает эксклюзивное право собственности на блокировку файлов.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Эффекты:Вызывающий поток пытается получить право собственности на файл блокировки, и если другой поток имеет исключительное право собственности на файл блокировки, ждет, пока он может получить право собственности.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Поток вызова пытается приобрести съемное право собственности на замок файла, не дожидаясь. Если ни один другой поток не имеет исключительного права собственности на блокировку файлов, это удается.
Возвращение:Если он может приобрести сельскохозяйственную собственность, немедленно возвращается правда. Если придется подождать, верните ложную информацию.
Броски:межпроцессное_исключениепо ошибке.
Эффекты:Вызывающий поток пытается приобрести съемное право собственности на блокировку файлов, ожидая, если это необходимо, пока другой поток не получит эксклюзивное право собственности на блокировку файлов или не будет достигнуто время abs_time.
Возвращение:Если приобретается сельскохозяйственная собственность, возвращается правда. В противном случае возврат ложный.
Броски:межпроцессное_исключениепо ошибке.
Предварительное условие:Нить должна иметь съемное право собственности на замок файла.
Эффекты:Позывной поток освобождает сепарабельное владение блокировкой файлов.
Броски:Исключение, полученное изinterprocess_ Exceptionпо ошибке.
Дополнительные методы блокировки файлов, пожалуйста<file_lock
reference
>.
![]() | Important |
---|---|
< |
<scoped_lock
>и<sharable_lock
>могут быть использованы для облегчения блокировки файлов при наличии исключений, как и в случае с мутексами:
#include <boost/interprocess/sync/file_lock.hpp> #include <boost/interprocess/sync/sharable_lock.hpp> //... using namespace boost::interprocess; //This process reads the file // ... //Open the file lock file_lock f_lock("my_file"); { //Construct a sharable lock with the filel lock. //This will call "f_lock.sharable_lock()". sharable_lock<file_lock> sh_lock(f_lock); //Now read the file... //The sharable lock is automatically released by //sh_lock's destructor }
#include <boost/interprocess/sync/file_lock.hpp> #include <boost/interprocess/sync/scoped_lock.hpp> //... using namespace boost::interprocess; //This process writes the file // ... //Open the file lock file_lock f_lock("my_file"); { //Construct a sharable lock with the filel lock. //This will call "f_lock.lock()". scoped_lock<file_lock> e_lock(f_lock); //Now write the file... //The exclusive lock is automatically released by //e_lock's destructor }
Тем не менее, передача блокировок допускается только между одним и тем же типом замков, то есть от съемного замка к другому съемному замку или от сумчатого замка к другому сумчатому замку. Перенос с ограниченного замка на сепарабельный замок не допускается, поскольку<file_lock
>не имеет функций продвижения или демонтажа замка, таких как<unlock_and_lock_sharable()
>. Это приведет к ошибке компиляции:
//Open the file lock file_lock f_lock("my_file"); scoped_lock<file_lock> e_lock(f_lock); //Compilation error, f_lock has no "unlock_and_lock_sharable()" member! sharable_lock<file_lock> e_lock(move(f_lock));
Если вы планируете использовать замки файлов так же, как и названные mutexes, будьте осторожны, потому что портативные замки файлов имеют ограничения синхронизации, в основном потому, что различные реализации (POSIX, Windows) предлагают разные гарантии. Межпроцессные блокировки файлов имеют следующие ограничения:
file_lock
>две нити из одного и того же процесса.file_lock
>, указывающих на один и тот же файл.Первое ограничение исходит в основном от POSIX, поскольку ручка файла является атрибутом каждого процесса, а не атрибутом одной строки. Это означает, что если поток использует объект<file_lock
>для блокировки файла, другие потоки будут видеть файл заблокированным. Механизм блокировки файлов Windows, с другой стороны, предлагает гарантии синхронизации потоков, поэтому поток, пытающийся заблокировать уже заблокированный файл, будет блокироваться.
Второе ограничение связано с тем, что состояние синхронизации блокировки файлов связано с одним дескриптором файла в Windows. Это означает, что при создании двух объектов<file_lock
>, указывающих на один и тот же файл, синхронизация не гарантируется. В POSIX, когда два дескриптора файлов используются для блокировки файла, если дескриптор закрыт, все замки файлов, установленные процессом вызова, очищаются.
Подводя итог, если вы планируете использовать портативную блокировку файлов в своих процессах, используйте следующие ограничения:
file_lock
>. 1128Как мы видели, блокировка файлов может быть полезна для синхронизации двух процессов, ноубедитесь, что данные записаны в файл, прежде чем разблокировать замок файла. Обратите внимание, что классы iostream выполняют некоторую буферизацию, поэтому, если вы хотите убедиться, что другие процессы могут видеть данные, которые вы написали, у вас есть следующие альтернативы:
fflush
>, если вы используете стандартные функции C или функцию<flush()
>при использовании C++ iostreams. В Windows вы даже не можете использовать другой класс для доступа к одному и тому же файлу.//... using namespace boost::interprocess; //This process writes the file // ... //Open the file lock fstream file("my_file") file_lock f_lock("my_lock_file"); { scoped_lock<file_lock> e_lock(f_lock); //Now write the file... //Flush data before unlocking the exclusive lock file.flush(); }
Очередь сообщений похожа на список сообщений. Нити могут помещать сообщения в очередь, и они также могут удалять сообщения из очереди. Каждое сообщение может также иметьприоритет, так что сообщения с более высоким приоритетом читаются перед сообщениями с более низким приоритетом. Каждое сообщение имеет некоторые атрибуты:
Нить может отправлять сообщение или принимать сообщение из очереди сообщения, используя 3 метода:
Очередь сообщенийпросто копирует необработанные байты между процессамии не отправляет объекты. Это означает, что если мы хотим отправить объект с помощью очереди сообщений, объект должен быть двоичным сериализуемым. Например, мы можем посылать целые числа между процессами, нонеа<std::string
>. Вы должны использоватьBoost.Serializationили использовать расширенныемеханизмы Boost.Interprocessдля отправки сложных данных между процессами.
Очередь сообщенийBoost.Interprocess- это именованная межпроцессная связь: очередь сообщений создается с именем и открывается именем, как файл. При создании очереди сообщений пользователь должен указать максимальный размер сообщения и максимальный номер сообщения, который может хранить очередь сообщений. Эти параметры определяют ресурсы (например, размер общей памяти, используемой для реализации очереди сообщений, если используется общая память).
using boost::interprocess; //Create a message_queue. If the queue //exists throws an exception message_queue mq (create_only //only create ,"message_queue" //name ,100 //max message number ,100 //max message size );
using boost::interprocess; //Creates or opens a message_queue. If the queue //does not exist creates it, otherwise opens it. //Message number and size are ignored if the queue //is opened message_queue mq (open_or_create //open or create ,"message_queue" //name ,100 //max message number ,100 //max message size );
using boost::interprocess; //Opens a message_queue. If the queue //does not exist throws an exception. message_queue mq (open_only //only open ,"message_queue" //name );
Очередь сообщений явно удаляется, вызывая статическую функцию<remove
>:
using boost::interprocess; message_queue::remove("message_queue");
Функция может выйти из строя, если очередь сообщений все еще используется любым процессом.
Чтобы использовать очередь сообщений, вы должны включить следующий заголовок:
#include <boost/interprocess/ipc/message_queue.hpp>
В следующем примере первый процесс создает очередь сообщений и записывает на нее множество целых чисел. Другой процесс просто считывает массив и проверяет правильность порядкового номера. Это первый процесс:
#include <boost/interprocess/ipc/message_queue.hpp> #include <iostream> #include <vector> using namespace boost::interprocess; int main () { try{ //Erase previous message queue message_queue::remove("message_queue"); //Create a message_queue. message_queue mq (create_only //only create ,"message_queue" //name ,100 //max message number ,sizeof(int) //max message size ); //Send 100 numbers for(int i = 0; i < 100; ++i){ mq.send(&i, sizeof(i), 0); } } catch(interprocess_exception &ex){ std::cout << ex.what() << std::endl; return 1; } return 0; }
Это второй процесс:
#include <boost/interprocess/ipc/message_queue.hpp> #include <iostream> #include <vector> using namespace boost::interprocess; int main () { try{ //Open a message queue. message_queue mq (open_only //only create ,"message_queue" //name ); unsigned int priority; message_queue::size_type recvd_size; //Receive 100 numbers for(int i = 0; i < 100; ++i){ int number; mq.receive(&number, sizeof(number), recvd_size, priority); if(number != i || recvd_size != sizeof(number)) return 1; } } catch(interprocess_exception &ex){ message_queue::remove("message_queue"); std::cout << ex.what() << std::endl; return 1; } message_queue::remove("message_queue"); return 0; }
Чтобы узнать больше об этом классе и всех его операциях, см. ссылку на класс<message_queue
>.
Статья Synchronization mechanisms раздела The Boost C++ Libraries BoostBook Documentation Subset Chapter 16. Boost.Interprocess может быть полезна для разработчиков на c++ и boost.
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.
:: Главная :: Chapter 16. Boost.Interprocess ::
реклама |