until done

}

//

В листинге 4.9 начальный поток создает оба потока: «изготовителя» и «потребителя». Поток- «изготовитель» содержит цикл, в котором после выполнения некоторых действий блокируется мьютекс для совместно используемой очереди, чтобы поместить в нее подготовленные для потребителя данные. После этого «изготовитель» деблокирует мьютекс и посылает сигнал потоку- «потребителю» о том, что ожидаемые им данные уже находятся в очереди. Поток- «изготовитель» выполняет итерации цикла до тех пор, пока не будет выполне н а вся работа. Поток- «потребитель» также выполняет цикл, в котором он приостанавливается до тех пор, пока не получит сигнал. Во внутреннем цикле поток- «потребитель» обрабатывает все данные до тех пор, пока не опустеет очередь. Он блокирует мьютекс для разде л яемой очереди перед извлечением из нее данных и деблокирует мьютекс после этого. Затем он выполняет обработку извлеченных данных. В программе 4.6 поток-«потребитель» помещает свои результаты в файл. Вместо файла может быть использована другая структура данных. Зачастую потоки-«потребители» играют две роли: как потребителя, так и изготовителя. Сначала возможно «исполнение» роли потребителя необработанных данных, подготовленных потоком-«изготовителем», а затем поток играет роль «изготовителя», когда он обрабатывает данные, сохраняемые в другой совместно используемой очереди, «потребляемой» другим потоком.

Создание многопоточных объектов

Модели делегирования, равноправных потоков, конвейера и типа «изготовитель» - «потребитель» предлагают деление программы на несколько потоков с помощью функций. При использовании объектов функции-члены могут создавать потоки выполнения нескольких задач. Потоки используются для выполнения кода от имени объекта: посредством отдельных функций и функций-членов.

В любом случае потоки объявляются в рамках объекта и создаются одной из функций-членов (например, конструктором). Потоки могут затем выполнять некоторые независимые функции (функции, определенные вне объекта), которые вызывают функции-члены глобальных объектов. Это — один из способов создания многопоточного объекта. Пример многопоточного объекта представлен в листинге 4.10.

// Листинг 4.11 . Объявление и определение многопоточного

// объекта

#include <pthread.h>

#include <iostream>

#include <unistd.h>

void *taskl(void *);

void *task2(void *);

class multithreaded_object {

pthread_t Threadl,

Thread2; public:

multithreaded_object(void);

int cl(void);

int c2(void);

//.. .

);

multithreaded_object::multithreaded_object(void) {

//. . .

pthread_create(&Threadl, NULL, taskl, NULL); pthread_create(&Thread2 , NULL, task2 , NULL);

pthread_join(Threadl, NULL);

pthread_join(Thread2 , NULL);

//. . .

}

int multithreaded_object::cl(void) {

// Выполнение действий,

return(1);

}

int multithreaded_object::c2(void) {

// Выполнение действий,

return(1);

}

multithreaded_object MObj;

void *taskl(void *) {

//...

MObj.cl() ; return(NULL) ;

}

void *task2(void *) {

//...

M0bj.c2(); return(NULL) ;

}

В листинге 4.11 в классе multithread_object объявляются два потока. Они создаются и присоединяются к основному потоку в конструкторе этого класса. Поток Thread1 выполняет функцию task1 (), а поток Thread2 — функцию task2 (). Функции taskl () и task2 () затем вызывают функции-члены глобального объекта MObj.

Резюме

В последовательной программе всю нагрузку можно разделить между отдельными подпрограммами таким образом, чтобы выполнение очередной подпрограммы было возможно только после завершения предыдущей. Существует и другая организация программ, когда, например, вся работа выполняется в виде мини-программ в рамках основной программы, причем эти мини-программы выполняются параллельно основной. Такие мини-программы могут быть реализованы как процессы или потоки. Если в реализации используются процессы, то каждый процесс должен иметь собственное адресное пространство, а если процессы должны взаимодействовать между собой, то такая реализация требует обеспечения механизма межпроцессного взаимодействия. Для потоков, разделяющих адресное пространство одного процесса, не нужны специальные методы взаимодействия. Но для защиты совместно используемой памяти (чтобы не допустить возникновения условий «гонок») необходимо использоватьтакие механизмы синхронизации, как мьютексы.

Существует ряд моделей, которые можно использовать для делегирования работы потокам и управления их созданием и аннулированием. В модели делегирования один поток (управляющий) создает другие потоки (рабочие) и назначает им задачи. Управляющий поток ожидает до тех пор, пока каждый рабочий поток не завершит свою задачу. При использовании модели равноправных узлов есть один поток, который изначально создает все потоки, необходимые для выполнения всех задач, причем этот поток считается рабочим потоком, поскольку он не осуществляет никакого делегирования. Все потоки в этой

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату