Программирование >>  Разработка устойчивых систем 

1 ... 176 177 178 [ 179 ] 180 181 182 ... 196


int mainO { cout Press <Enter> to quit endl: try {

CountedPtr<ThreadLocal Variabl es>

tlv(new ThreadLocalVariables): const int SZ = 5: ThreadedExecutor executor: for(int i = 0: i < SZ: i++)

executor.execute(new Accessor(tlv. i)): Cin.getO:

tlv->cancel(): Завершение всех задач Accessor } catch(Synchronization ExceptionS e) { cerr e.whatO endl:

} III-

При создании объекта ThreadLocal посредством специализации шаблона для обращения к содержимому объекта могут использоваться только функции get() и set(). Функция get() возвращает копию объекта, связанного с программным потоком, а функция set() подставляет свой аргумент в объект, ассоциированный с данным потоком, и возвращает прежний объект. Примеры применения этих функций встречаются в функциях increment() и get() класса ThreadLocalVariables.

Так как объект tlv совместно используется несколькими объектами Accessor, он реализует интерфейс Cancelable, чтобы объектам Accessor можно было сообщить о завершении работы системы.

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

Завершение задач

в предыдущих примерах для завершения задач использовались флаги или интерфейс Cancelable. Обычно этого бывает достаточно, но в некоторых ситуациях нужно, чтобы задачи завершались быстрее. В этом разделе будут рассматриваться особенности и потенциальные проблемы, возникающие при таком завершении.

Начнем с программы, которая не только демонстрирует проблемы с ускоренным завершением, но и является дополнительным примером совместного использования ресурсов. Но прежде чем переходить к этому примеру, мы должны решить проблему коллизий в потоках ввода-вывода.

CountedPtr<ThreadLocalVariаЫes> tl v: public:

Accessor(CountedPtr<ThreadLocalVariables>& tl. int idn) : id(idn). tlv(tl) {} void runO { while(Itlv->isCanceled()) {

tlv->increment():

cout *th1s endl:

friend ostreamS operator (ostreamS os, AccessorS a) { return OS # a.id : a.tlv->get():



Предотвращение коллизий в потоках ввода-вывода

Возможно, вы заметили, что в предыдущих примерах выводимые данные иногда искажались. Система потоков ввода-вывода С++ проектировалась без учета многопоточности, поэтому ничто не мешало результатам одного потока смешаться с результатами другого. А это означает, что при написании приложений необходимо синхронизировать операции ввода-вывода.

Чтобы решить проблему, нужно сначала сгенерировать весь выходной пакет, а затем решить, когда отправить его на консоль. В одном из простых решений информация записывается в ostringstream, а затем один объект с мутексом синхронизирует вывод между всеми программными потоками:

: Cll:Display.h

Предотвращение коллизий при выводе

#ifndef DISPLAY H

#def1ne DISPLAY H

linclude <iostream>

linclude <sstream>

linclude zthread/Mutex.h

linclude zthread/Guard.h

class Display { Один объект совместно используется

ZThread::Mutex iolock: всеми потоками ввода-вывода, public:

void outputCstd::ostringstream& os) { ZThread::Guard<ZThread::Mutex> g(iolock): std: :cout os.strO:

lendif DISPLAY H /:-

В этом варианте стандартные операторные функции operator () определены заранее, а объект строится в памяти с применением знакомых потоковых операторов. Когда задача хочет вывести сообщение, она создает временный объект ostringstream и использует его для построения нужного выходного сообщения. При вызове output() мутекс предотвращает запись в объект Display из нескольких программных потоков (как будет показано далее, в программе должен существовать только один объект Display).

Этот пример всего лишь демонстрирует базовый принцип, но при желании его можно усовершенствовать. Например, чтобы обеспечить выполнение требования о наличии только одного объекта Display в программе, можно преобразовать его в Синглет (в библиотеку ZThread входит шаблон Singleton, предназначенный для реализации Синглетов).

Подсчет посетителей

в следующей программе требуется узнать, сколько посетителей ежедневно заходит в парк. На каждом проходе установлена вертушка или похожий механизм. После увеличения отдельного счетчика вращений увеличивается общий счетчик, представляющий суммарное количество посетителей парка.

: СП: Ornamental Garden, срр {L} ZThread linclude <vector>



class Entrance : public Runnable { CountedPtr<Count> count: CountedPtr<D1splay> display: int number: int id:

bool waitingForCancel: public:

Entrance(CountedPtr<Count>& cnt, CountedPtr<Display>& disp. int idn)

: count(cnt). display(disp). id(idn). number(O), waitingForCancel(false) {}

void runO {

#1 nclude <cstdl1b>

#i nclude <ctime>

finclude Display.h

finclude zthread/Thread.h

finclude zthread/FastMutex.h

finclude zthread/Guard.h

finclude Zthread/ThreadedExecutor.h

finclude zthread/CountedPtr.h

using namespace ZThread:

using namespace std:

class Count : public Cancelable { FastMutex lock: int count:

bool paused, canceled: public:

CountO : count (0). paused(false), canceled(false) {} int incrementО {

Если закомментировать следующую строку, подсчет перестает работать: Gua rd<Fa stMutex> g(1оск): int temp = count :

if(rand() 2 == 0) Передача управления в половине случаев

Thread::yield(): return (count = ++temp):

int valueO { Guard<FastMutex> g(lock): return count:

void cancel О { Guard<FastMutex> g(lock): canceled = true:

bool IsCanceledO { Guard<FastMutex> g(lock): return canceled:

bool pauseO { Guard<FastMutex> g(lock): paused = true:

bool isPausedO { Guard<FastMutex> g(lock): return paused:



1 ... 176 177 178 [ 179 ] 180 181 182 ... 196

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика