// Thread 1:
sharedMemory = std::make_shared<Immutable>(1);
// Thread 2:
DoSomething(*sharedMemory);
Это не пример непреложности. Общее состояние sharedMemory
: не неизменный.
Неизменяемость была бы двумя разными потоками, как для чтения sharedMemory
, построенного до либо нить существовала.
Если они хотят внести в него изменения, они возвращают изменения.
Обязательства по неизменности все общее состояние не может быть изменено. Вы все равно можете передавать данные в поток (через аргументы threading) или передавать данные из потока (через future
)
Вы можете даже сделать изолированное измененное общее состояние, как очередь задач для рабочих потоков, чтобы потреблять. Здесь сама очередь изменчива и тщательно написана. Рабочие потоки потребляют задачи.
Но задачи работают только с неизменяемым общим состоянием и возвращают данные в другие потоки через future
, которые ожидают возврата задачи.
Мягкая форма изменчивости - это фьючерсы.
std::shared_future<std::shared_ptr<Immutable>> sharedMemory = create_shared_memory_async();
std::future<void> r = DoSomethingWithSharedMemoryAsync(sharedMemory);
// in DoSomethingWithSharedMemory
auto sharedMemoryV = sharedMemory.get(); // blocks until memory is ready
DoSomething(*sharedMemory);
Это не полностью неизменяемое общее состояние.
Вот другое нечистое использование неизменного общего состояния:
cow_ptr<Document> ptr = GetCurrentDocument();
std::future<error_code> print = print_document_async(ptr);
std::future<error_code> backup = backup_document_async(ptr);
ptr.write().name = "new name";
cow_ptr
копия на указателе записи. Он допускает постоянный доступ только для чтения.
Если вы хотите изменить его, вы вызываете метод .write()
. Если вы являетесь единственным владельцем этого общего ресурса, он просто дает вам доступ на запись. В противном случае он клонирует ресурс и гарантирует его уникальность, а затем дает вам доступ на запись.
Две различные нити, print
и backup
темы, есть доступ к ptr
. Они не могут изменять какие-либо данные, которые может видеть другой поток (им разрешено редактировать его, но это только изменяет их локальную копию данных).
Назад в основной поток, мы переименуем документ в новое имя. Ни в потоках печати, ни в резервной копии это не увидит, поскольку они имеют неизменяемую (логическую) копию.
Два потока и доступ к тому же ptr
переменному не является законным, но они могут получить доступ к скопировать этой ptr
переменных.
Если документ сам был построен из cow_ptr
s повсюду, «копия» документа будет копировать только внутренние cow_ptr
s; т. е. атомный приращение нескольких контрольных отсчетов, а не всего состояния.
Изменение глубоких элементов потребует панировочных сухарей; вам нужен breadcrumb_ptr
, который отслеживает маршрут, необходимый для достижения заданного cow_ptr
. Затем .write()
на нем продолжит дублировать все, вплоть до корня «документа», возможно, заменяя каждый указатель (с вызовом .write()
).
В этой системе у нас есть возможность обмениваться чрезвычайно большими и сложными формами изображений данных с O (1) стоимостью между потоками, а единственными служебными данными синхронизации являются подсчет ссылок.
Это еще не чистая неизменность. Но на практике эта нечистая форма неизменности дает много преимуществ и позволяет вам эффективно и безопасно делать вещи, которые в противном случае чрезвычайно опасны или дороги.
Я думаю, идея состоит в том, чтобы создать общий объект перед запуском нескольких потоков. – Justin