Программирование >>  Структура ядра и системные вызовы 

1 ... 89 90 91 [ 92 ] 93 94 95 ... 98


потоков, все равно может возникнуть необходимость в пользовательских данных для конкретных потоков. Так, пользователи, разрабатывающие пакет утилит (например, новый пакет GUI), который могут использовать другие программисты, возможно, захотят определить собственные версии еггпо, чтобы иметь возможность проверить, не содержит ли эта переменная кода ошибки, возвращенной утилитами. При этом, однако, функции пакета могут одновременно вызываться несколькими потоками, поэтому необходимо, чтобы переменная еггпо определялась функциями конкретно для каждого потока. Ниже мы покажем, как это делается, а сейчас перечислим функции, определенные в библиотеке потоков Sun для управления данными потоков.

Функция

Назначение

thr keycreate

thr setspecific

thr getspecific

Определяет общую переменную ( юхюч ) для всех потоков Заносит данные потока в ключ Извлекает данные потока из ключа

Прототипы этих функций выглядят следующим образом:

#include <thread.h>

int thr keycreate (thread key t* keyp, void (*destr)(void*)); int thrjsetspecific (thread key t key, void* valuep); int thrjgetspedfic (thread key t key, void* valuep);

Значение аргумента keyp представляет собой адрес переменной типа thread key t. Эта переменная инициализируется функцией thr keycreate. Необязательный аргумент destr - это адрес определяемой пользователем функции, которая может вызываться для уничтожения данных после завершения потока, зарегистрировавшего эти данные в переменной *кеур. Значение этого аргумента, передаваемое в функцию destr, представляет собой адрес данных завершающегося потока, зарегистрированных в *кеур с помощью функции thr setspecific.

Функция thrsetspecific вызывается потоком для регистрации данных в ключе . Аргумент key содержит ключ , в котором необходимо зарегистрировать данные. Аргумент vciluep содержит адрес данных потока. Ютюч может одновременно содержать несколько значений, но только по одному значению на поток.

Для выборки данных вызывающего потока, зарегистрированных в ключе , обозначенном аргументом key, вызьшается функция thrsetspecific. Данные потока возвращается через аргумент valuep.

В заголовке файла pkg.h определяется класс данных, который может одновременно использоваться несколькими потоками. В частности, этот класс определяет объект eirno и объект ofstream для каждого потока, поэтому

никаких конфликтов между потоками, вызывающими одни и те же функции класса, не возникает. Приведем содержимое файла pkg.h:

fifndef PKG H fdefine PKG H finclude <fstream.h> finclude <stdio.h> finclude <thread.h>

/* запись для хранения набора данных конкретного потока */ class thr data {

int errno; errno для потока выполнения

ofstreams ofs; поток вывода для потока выполнения

/* прочее */ public:

/* функция-конструктор */ thr data( int errval, ofstreamS os) : errno(errval), ofs(os) (};

/* функция-деструктор */ ~tlir data() ( ofs.closeO; };

/* возвращает значение errno для потока */ int& errval О { return errno;

/* возвратить указатель на поток вывода для потока

выполнения */ ofstreamS os()( return,ofs; );

/* другие функции-члены */

/* Класс пакета утилит*)*

class Xpackage {

tliread key t key; ключ для всех потоков ofstream ocerr; выходной поток по умолчанию

/* другие данные */ public:

/* вызывается, когда поток уничтожается. Данные потока

удаляются */ friend void destr( void* valueP ) (

tlir data *pDat * (thr data*) valueP; delete pDat;

/* функция-конструктор */ Xpackage0 : ocerr( err.log )

if (tlir keycreate (skey, destr)) perror( thr create );



/* функция-деструктор */ ~Храскадв() ( осегг.close(); }; ,

/* вызывается, когда поток открывается */ void new thread( int errval, ofstreams os ) (

thr data *pDat;

/* распределение памяти для данных потока */ pDat = new thr data(errval, os); if (thr setspecific (key,pDat)) . perror ( thr setspecific )

/* устанавливает errno потока и возвращаемое значение */

int set errno( int rc )

thr data *pDat;

if (t!ir getspecific(key, (void**) SpDat) )

perror( thr getspecific ); else pDat->errval0 = rc; return rc==0 ? 0 : -1;

/* возвращает текущее значение errno для потока int errnoО

. thr data *pDat;

if (!thrgetspeeific(key,(void**)SpDat))

return pDat->errval0;

perror ( tlir getspecific ); return -1;

/* возвращает указатель на поток вывода данного потока

выполнения */ of streams os()

thr data *pDat;

if (!thr getspecific(key,(void**)SpDat))

return pDat->os 0;

perror( thr getspecific ); return ocerr;

/* пример функции из пакета */ int chgErrno(int new val ) (

return set errno( new val )*,

>;

/* другие функции из пакета */

#endif

Все данные потоков хранятся в записи типа thrjdata. В этой записи содержатся объекты егто и ofstream, которые в каждом потоке являются закрытыми (private). При желании пользователи могут переопределить класс thr data так, чтобы он содержал дополнительные данные.

В каждой пользовательской программе должна присутствовать глобальная переменная типа Xpackage. При запуске программы вызывается конструктор Xpackager.Xpackage, который инициализирует переменную Xpackager.key, совместно используемую всеми потоками процесса. Переменная Xpackage.-жегг обозначает поток вывода по умолчанию в случае, если определенный в потоке выполнения поток вывода не может быть открыт. Если пользователь хочет сохранять в процессе данные потоков выполнения других типов, он может определить несколько переменных типа Xpackage, по одной для каждого типа данных.

Функции пакета вызывают Xpackage::set ermo, чтобы установить значение егто для вызывающего потока. Функция Xpackage::егто вызывается потоком для получения конкретного значения переменной errno. Функция Храск-age::os возвращает указатель на поток вывода для данного потока выполнения.

Функция Xpackage::chgErmo в приведенном примере только устанавливает значение егто для каждого потока равным сумме идентификатора потока и числа 100. Как и все остальные определенные в пакете функции, в случае

успешного вьшолнения она возврашает О, а в случае неудачи--1 (в егто

конкретного потока соответствующим образом устанавливается код ошибки).

Функция destr вызывается каждый раз, когда поток завершается. Эта функция удаляет данные потока типа thr data. Если поток зарегистрировал несколько записей типа thrjdata в нескольких переменных типа Xpackage, то функция destr вызывается несколько раз, т.е. для каждого элемента данных типа thr data, принадлежащего завершающемуся потоку.

Приведенный ниже файл threrrno.C - это пример пользовательской программы, в которой используется класс Xpackage.

#include pkg.h

Xpackage pkgObj; /* объект пакета */

/* функция, выполняемая каждым потоком */

void* funcl( void* argp )

int *rcp = new int(l);



/* открыть поток вывода потока выполнения */

ofstream ofs ((char*)argp);

if (!ofs) thr exit((void**)Srcp);

/* инициализация данных потока */ pJcgObj .new thread ( 0, ofs ) ;

/* выполнить работу с помощью функций пакета */

pkgObj.chgErrno( 100 ); /* изменить errno потока выполнения*/

/* записать данные в поток вывода потока выполнения */ pkgObj.osO (char*) argp [

(int) thr self О ] finishes\n ;,

/* поток закрывается; установить код возврата */ *гср = pkgObj .errno о ; thr exit(rep); return 0;

/* главная функция потока */ int main(int argc, char** argv) {

thread t tid; int *rc;

/* создать поток для каждого аргумента командной строки */ while (-argc > 0)

if (thr create (0,0, fund, (void*) argv [argc], 0, stid))

perror( thr create );

/* ждать завершения всех потоков */ while (! thrjoin (О, stid, (void**)&rc)) (

cerr thread! (int)tid exists. rc= *rc endl; delete rc;

/* завершить главный поток */ thr exit(0); return 0;

Эта программа вызывается с одним или несколькими именами файлов в качестве аргументов командной строки. Каждый аргумент - это имя файла, в который направлен вывод соответствующего потока выполнения. Для каждого аргумента главный поток создает новый поток, чтобы выполнить функцию Умлс/. Аргумент функции fund - имя файла, в который направлен вывод нового потока выполнения. После создания всех потоков выполнения главный поток ждет их завершения, а потом завершается сам.

Начиная выполнять функцию fund, поток определяет объект ofstream, обозначающий заданный выходной файл. Затем он вызывает функцию pkgObj.newjhread, которая выделяет область памяти для хранения данных потока и в которой содержится объект ofstream. Значение еггпо устанавливается в нуль. После этого поток вызывает функции пакета для выполнения основных операций. Затем вызывается функция pkgObj.chgErrno, которая устанавливает значение еггпо потока равным сумме его идентификатора и числа 100. В результате значение егто каждого потока, который выполняет функцию fund, уникально. Затем поток вызывает функцию pkjObj.os, которая возвращает указатель на объект потока вывода и посылает туда имя выходного файла и идентификатор потока выполнения. Поток выполнения завершается, указывая свое значение еггпо как аргумент вызова функции thr exit.

Ниже приведен пример выполнения программы thrermo и полученные результаты:

% СС thr errni.C -о thr errno -Ithread % threrrno а b thread: 5 exits. rc=105 thread: 4 exits. rc=104 % cat a

a [5] finishes % cat b

b [4] finishes

Здесь программа thr ermo вызывается с именами двух файлов: avib. Для выполнения функций fund создаются два потока. Первый поток имеет идентификатор 5 и создает выходной файл с именем а и содержимым а [5] finishes. Этот поток завершается с кодом выхода 104. Идентификатор второго потока - 4. Он создает файл с именем b и содержимым b [4]finishes. Его код выхода - 104.

13.7. Среда многопотокового программирования

Для поддержки многопотокового программирования в ОС Solaris имеется библиотека потоков, которая позволяет пользователям создавать в своих программах потоки выполнения и управлять ими. Есть также модификации стандартных библиотек, например имеются реентерабельные версии многих популярных библиотечных функций. Глобальные переменные (например, еггпо), экспортируемые из стандартных библиотек, определяются динамически для каждого потока, который ими пользуется. Все это позволяет успешно использовать стандартные библиотеки одновременно в нескольких потоках.

Кроме того, в ОС Solaris модифицировано ядро, что обеспечивает поддержку симметричной многопроцессорной обработки и планирования облегченных процессов. Имеются также многопотоковые версии команд debugger и truss, которые отлаживают и трассируют выполнение отдельных



1 ... 89 90 91 [ 92 ] 93 94 95 ... 98

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