то вызов функции dequeue блокируется на элементе списка tail->value, так как при добавлении в конец списка сообщения (tail->value=msg) в списке будет прочитан указатель на следующий элемент (tail->next) прежде, чем в нем будет установлена ссылка на недавно созданный элемент.
Переменная типа sync позволяет синхронизировать передачу данных от генератора потребителю. Однако в некоторых задачах встречается необходимость не синхронизированной передачи данных потребителю от нескольких производителей. При этом возникает опасность одновременного обращения к одной и той же структуре нескольких процессов. Поэтому необходим механизм, который бы гарантировал не синхронизированное обращение к данным очереди одновременно лишь одному процессу.
Механизм взаимного исключения (Mutual Exclusion – mutеx) в СС++ реализуется с помощью ключевого слова atomic (неделимый). Функции, являющиеся членами объекта и объявленные неделимыми, не будут вклиниваться в выполнение любой другой неделимой функции того же самого объекта.
Например, чтобы позволить множеству генераторов данных добавлять данные в конец одной и той же очереди, необходимо в объявление функции, поставляющей данные, вставить ключевое слово atomic следующим образом:
atomic void Queue::enqueue(int msg)
{
tail->next = new IntQData;
tail->value = msg;
tail = tail->next;
}
Такое определение гарантирует, что, даже если производители данных попытаются добавлять данные в конец к той же самой очереди одновременно, то фактически будет происходить постановка операций в очередь. Операции при этом будут выполняться в некотором последовательном порядке.
В классе ios С++ для передачи от файла к файлу данных точно установленного типа в библиотеке <iostream.h> определены инфиксные операторы << и >> , вставляемые в определения следующим образом:
ostream& operator<<(ostream&, const TYPE& obj_in);
istream& operator>>(istream&, TYPE& obj_out);
С помощью этих форм описываются процессы записи и чтения не только для простых, предопределенных типов, но и для определяемых программистом комплексных типов, что расширяет диапазон модульности.
CC++ использует аналогичный механизм для взаимодействующих структур данных, расположенных в различных процессорных объектах. С каждым типом данных CC++ ассоциирует две функции передачи данных, которые определяют, как переместить тот или иной тип данных другому процессорному объекту. Функция
CCVoid& operator<<(CCVoid&, constTYPE& obj_in);
определяет, как объект TYPE должен быть упакован для связи. По указанному типу перемещаемых данных компилятор автоматически распознает, какого типа параметры и какой тип возвращаемого значения должны быть установлены, чтобы выполнить запрос на RPC. Точно так же функция приема
CCVoid& operator>>(CCVoid&, TYPE& obj_out);
определяет, как объект TYPE должен быть распакован. Определяется это на момент трансляции, когда объект TYPE принимается от другого процессорного объекта. После завершения запроса RPC obj_out будет копией obj_in, использованного в исходном процессорном объекте как параметр у функции передачи operator<<.
Рисунок 3.6 поясняет действие функций передачи определенного пользователем типа данных DVector с одного процессорного объекта на другой.
class DVector
{
int length; double *elements;
friend CCVoid& operator<<(CCVoid&, const DVector&);
friend CCVoid& operator>>(CCVoid&, DVector&);
friend ostream& operator<<(ostream&, const DVector&);
friend istream& operator>>(istream&, DVector&);
};
CCVoid& operator<<(CCVoid& v, const DVector& input)
{
v << input.length; // Отсылка значения length
for (int i=0; i<input.length; i++)
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.