Указатели global и переменные типа sync позволяют осуществить ряд полезных механизмов связи. В качестве примера рассмотрим организацию простой общедоступной очереди, как класса, в котором реализуется канал связи между двумя одновременно выполняющимися задачами – производителем и потребителем данных, снабдив обе задачи указателями на соответствующий объект.
Представим канал в виде очереди сообщений, в которую производитель данных может добавлять в конец очереди последовательность сообщений, а потребитель – удалять из начала очереди, ранее поступившие сообщения. Единственной реакцией синхронной связи будет блокировка потребителя, обратившегося за изъятием сообщения при пустой очереди.
Очевидным представлением очереди сообщений в CC++ является список связей, в котором каждая запись содержит сообщение плюс указатель на следующее сообщение.
В тексте 3.6 используется именно этот подход. В примере определяется класс Queue (очередь), который сохраняет указатели на голову и хвост очереди сообщений, представленной структурой в виде списка IntQData. Структура данных, управляемая в соответствии с текстом 3.6 показана на рисунке 3.5.
structIntQData
{ // Элемент списка содержит:
syncintvalue; // синхронизирующую переменную
structIntQData *next; // (т.е. сообщение) и указатель на
} // следующий элемент списка.
//---------------------------//
classQueue
{
public:
void enqueue(int);
int dequeue();
private:
voidQueue() // Инициализация единственного элемента
{ //Определение головы и
head = tail = newIntQData;// хвоста элемента очереди.
}
IntQData *head, *tail; // Объявление указателей на
} // на голову и хвост очереди.
//---------------------------//
voidQueue::enqueue(intmsg) // Определение функции,
{ // добавляющей записи:
tail->next = newIntQData; // размещение нового
tail->value = msg; // элемента списка, состо-
tail = tail->next; // ящего из сообщенияmsg
} // и указателя на хвост
//---------------------------//
intQueue::dequeue() //Определение функции изъятия
{ // сообщения из головы очереди:
intretval = head->value; // сохранение содержимого головы;
IntQData *newh = head->next; // сохранение указателя на хвост;
deletehead; // удаление в списке старой головы;
head = newh; // передвижка указателя на голову;
returnretval; // возвращение изъятого значения.
}
Рисунок 3.5. Представление класса “Очередь” в виде списка.
При первом входе в очередь читается содержимое сообщения. Операция чтения блокируется (приостанавливается), если список пуст, выполняя тем самым синхронизацию. Если список сообщений не пустой, то функция, изымающая сообщение, прочитывает первый элемент списка, стирает его и передвигает указатель первого элемента на следующий элемент списка. Аналогично, функция, добавляющая очередной элемент в конец списка, связывает его с предыдущим хвостовым элементом, помещает сообщение в поле текущего конца списка и устанавливает указатель конца очереди.
Порядок выполнения названных двух операций важен. Если расположить операции в ином порядке, а именно:
tail->value = msg;
tail->next = new IntQData;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.