Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Использование модели делегирования






 

Мы рассмотрели два подхода к реализации модели делегирования при разделении мы на потоки. Вспомним: в модели делегирования один поток (управляющий) создает другие потоки (рабочие) и назначает каждому из них задачу. Управляющий поток делегирует каждому рабочему потоку задачу, которую он должен выполнить, путем задания некоторой функции. При одном подходе управляющий поток создает рабочие потоки как результат запросов, обращенных к системе. Управляющий поток обрабатывает запрос каждого типа в цикле событий. Как только событие произойдет, будет создан рабочий поток и ему будет назначена задача. Функционирование цикла событий в управляющем потоке и создание рабочих потоков продемонстрировано в листинге 4 .5.

// Листинг 4.5. Подход 1: скелет программы реализации II модели управляющего и рабочих потоков

//...

pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER

int AvailableThreads

pthread_t Thread[Max_Threads]

void decrementThreadAvailability(void)

void incrementThreadAvailability(void)

int threadAvailability(void);

 

 

// boss thread

{

//...

if(sysconf(_SC_THREAD_THREADS_MAX) > 0){

AvailableThreads = sysconf(_SC_THREAD_THREADS_MAX)

}

else{

AvailableThreads = Default

}

 

int Count = 1;

 

loop while(Request Queue is not empty)

if(threadAvailability()){

Count++

decrementThreadAvailability()

classify request

switch(request type)

{

case X: pthread_create(& (Thread[Count])...taskX...)

case Y: pthread_create(& (Thread[Count])...taskY...)

case Z: pthread_create(& (Thread[Count])...taskZ...)

//...

}

}

else{

//free up thread resources

}

end loop

}

 

void *taskX(void *X)

{

// process X type request

incrementThreadAvailability()

return(NULL)

}

 

void *taskY(void *Y)

{

// process Y type request

incrementThreadAvailability()

return(NULL)

}

 

void *taskZ(void *Z)

{

// process Z type request

decrementThreadAvailability()

return(NULL)

}

 

В листинге 4.5 управляющий поток динамически создает поток для обработки каждого нового запроса, который поступает в систему. Однако существует ограничение на количество потоков (максимальное число потоков), которое можно создать в процессе. Для обработки n типов запросов существует n задач. Чтобы гарантировать, что максимальное число потоков на процесс не будет превышено, определяются следующие дополнительные функции:

threadAvailability()

incrementThreadAvailability()

decrementThreadAvailability()

В листинге 4.6 содержится псевдокод реализации этих функций.

// Листинг 4.6. Функции, которые управляют возможностью

// создания потоков

void incrementThreadAvailability(void)

{

//...

pthread_mutex_lock(& Mutex)

AvailableThreads++

pthread_mutex_unlock(& Mutex)

}

 

void decrementThreadAvailability(void)

{

//...

pthread_mutex_lock(& Mutex)

AvailableThreads—

pthread_mutex_unlock(& Mutex)

}

 

int threadAvailability(void)

{

//...

pthread_mutex_lock(& Mutex)

if(AvailableThreads > 1)

return 1

else

return 0

pthread_mutex_unlock(& Mutex)

}

Ф ункция threadAvailability() возвратит число 1, если максимально допустимое количество потоков для процесса еще не достигнуто. Эта функция опрашивает глобальную переменную ThreadAvailability, в которой хранится число потоков, еще доступных для процесса. Управляющий поток вызывает функцию decrementThreadAvailability(), которая декрементирует эту глобальную переменную до создания им рабочего потока. Каждый рабочий поток вызывает функцию incrementThreadAvailability(), которая инкрементирует глобальную переменную ThreadAvailability до начала его выполнения. Обе функции содержат обращение к функции pthread_mutex_lock () до получения доступа к этой глобальной переменной и обращение к функции pthread_mutex_unlock() после него. Если максимально допустимое количество потоков превышено, управляющий поток может отменить создание потока, если это возможно, или породить другой процесс, если это необходимо. Функции taskX(), taskY () и taskZ () выполняют код, предназначенный для обработки запроса соответствующего типа.

Другой подход к реализации модели делегирования состоит в создании управляющим потоком пула потоков, которым (вместо создания под каждый новый запрос нового потока) переназначаются новые запросы. Управляющий поток во время инициализации создает некоторое количество потоков, а затем каждый созданный поток приостанавливается до тех пор, пока в очередь не будет добавлен новый запрос. Управляющий поток для выделения запросов из очереди по-прежнему использует цикл событий. Но вместо создания нового потока для обслуживания очередного запроса, управляющий поток уведомляет уже существующий поток о необходимости обработки запроса. Этот подход к реализации модели делегирования представлен в листинге 4.7.

// Листинг 4.7. Подход 2: скелет программы реализации. модели управляющего и рабочих потоков

pthread_t Thread[N]

 

// boss thread

{

 

pthread_create(& (Thread[1]...taskX...);

pthread_create(& (Thread[2]...taskY...);

pthread_create(& (Thread[3]...taskZ...);

//...

 

loop while(Request Queue is not empty

get request

classify request

switch(request type)

{

case X:

enqueue request to XQueue

signal Thread[1]

 

case Y:

enqueue request to YQueue

signal Thread[2]

 

case Z:

enqueue request to ZQueue

signal Thread[3]

//...

}

 

end loop

}

 

void *taskX(void *X)

{

loop

suspend until awaken by boss

loop while XQueue is not empty

dequeue request

process request

 

end loop

until done

{

 

void *taskY(void *Y)

{

loop

suspend until awaken by boss

loop while YQueue is not empty

dequeue request

process request

end loop

until done

}

 

void *taskZ(void *Z)

{

loop

suspend until awaken by boss

loop while (ZQueue is not empty)

dequeue request

process request

end loop

until done

} //...

В листинге 4.7 управляющий поток создает N рабочих потоков (по одному для каждого типа задачи). Каждая задача связана с обработкой запросов некоторого типа В цикле событий управляющий поток извлекает запрос из очереди запросов, определяет его тип, ставит его в очередь запросов, соответствующую типу, а затем оправляет сигнал потоку, который обрабатывает запросы из этой очереди. Функции потоков также содержат циклы событий. Поток приостанавливается до тех пор, пока не получит сигнал от управляющего потока о существовании запроса в его очереди. После «пробуждения» (уже во внутреннем цикле) поток обрабатывает все запросы до тех пор, пока его очередь не опустеет.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.