|
Программирование >> Структура ядра и системные вызовы
thread list[num thEead++] tid; чг cout Thread: (int)tid created for msg: msg , [ host * l\n ; return RPC SUCCESS; /* Главная функция клиента */ int main(int argc, char* argv[}) 4-; я num thread=0; thread t tid; int *res; /* задать количество параллельных потоков */ if (thr setconcurrency(5)) perror( thr setoncurrency ); cout No. LPWs in process: getpidO is: thr getconcurrency0 endl; /* создать поток для передачи каждого сообщения */ while (add thread(num thread)==RPC SUCCESS) ; /* установить приоритет для каждого потока и запустить его */ for (int i=0; i < num thread; i++) thr setprio(thread list[i],i); -эт,- th irContinue (thread list [i]) ; I* ждать заверщения каждого потока */ у-ь while (!thr join(0,&tid, (void**)&res)) cerr thread: (int)tid , exited. rc= (*res) endl; delete res; /* заверщить главный поток */ thr exit(0); return 0; } , .у.: - R В этой программе клиентский процесс начинается с вызова функции thr concurrency, которая устанавливает число облегченных процессов равным пяти. Это значит, что в любой момент времени параллельно могут выполняться как минимум пять потоков. Процесс выясняет количество фактически созданных LWP с помощью функции thr getconcurrency и отображает эту информахщю на стандартном устройстве вывода. Затем процесс вызывает функцию addjhread до тех пор, пока она не возвратит нуль. Каждый раз при вызове эта функция получает от пользователя через стандартный ввод имя хост-машины и сообщение. Если встречается признак конца файла или ошибка ввода, функция возвращает в main Сиет ми * ярогр* м ва1*н на С+* для WWW нулевое значение, означающее окончание пользовательского ввода. Если входные данные выбраны успешно, функция addjhread вьщеляет память под хранение указанного пользователем имени хост-машины и сообщения в записи типа MSGREC. Затем она вызывает функцию thrjcreate для создания потока и вьшолнения функции sendmsg. Входным аргументом функции sendjnsg является адрес только что определенной переменной типа MSGREC. Этот поток создается со стеком, выделенным системой, и приостанавливается сразу же после создания. Идентификатор вновь созданного потока сохраняется в глобальном массиве thread list, и функция addjhread возвращает в main единицу, указывая таким образом на успешное вьшолнение. Если же поток не создался или если уже создано MAX THREAD потоков, функция возвращает в main нулевое значение, сигнализирующее об ошибке. После того как функция addjhread создаст все потоки, необходимые для обработки всех пользовательских входных данных, функция main (главный поток) просматривает массив thread list и устанавливает приоритет каждого потока. Идентификатор потока сохраняется в массиве со значением, связанным с позицией (индексом) потока в массиве. Так, первый поток в массиве имеет самый низкий приоритет, следующий поток имеет второй приоритет снизу и так далее. Функция main запускает каждый приостановленный поток с помощью функции thr continue. После этого функция main ждет завершения каждого потока и отображает на стандартном устройстве вывода идентификатор потока и код возврата. Каждый запущенный поток вьтолняет функцию sendjnsg. Сначала поток устанавливает свою сигнальную маску так, чтобы она включала все, кроме сигнала SIGHUP. Затем поток создает обработчик RPC-клиента, который будет соединяться с хост-сервером, чье имя задано во входном аргументе функции sendjnsg. Если обработчик RPC-клиента создан успешно, то поток вызывает функцию RPCcls::call, которая передает пользовательское сообщение на сервер. Сообщение выводится на системную консоль сервера. Наконец, поток освобождает память, в которой хранится имя хост-машины и сообщение, выделяет память для хранения возвращенного значения, после чего с помощью вызова thr exit возвращает эти динамические данные в функцию main. Код возврата хранится в динамически выделяемой памяти по той причине, что функция sendjnsg вьшолняется множеством потоков и каждый из них должен возвращать собственный код завершения. Поэтому возвращенное значение не может храниться в статической переменной, а должно помещаться в динамическую переменную, уникальную для каждого потока. Программа-сервер printmsg (msg svc2.Q и определение класса RPCjls, указанного в заголовке RPC.h, приведены в разделе 12.5. Новая программа-клиент msgjls2. С компилируется следующим образом: % СС -DSYSV4 msg cls2.C -о msg cls2 -Ithread -Insl Опции -Ithread и -Insl дают редактору связей указание скомпоновать объектный файл msgcls2.o с библиотекой потоков выполнения (libthread.so) и сетевой библиотекой (libnsl.co). Первая библиотека содержит объектные коды всех API потоков вьшолнения, а вторая - коды, связанные с RPC. Ейква 13. Многопотоковое програмитревание: Ниже показаны пример запуска клиентской программы и полученнью результаты. Слова, выделенные курсивом,- это входные данные, вводимые пользователем со стандартного устройства ввода, л, . ..<аи(,Ь . ии. % msg cls2 No. LWPs: 5 frui t happy day 4 Thread: 4 created for msg: happy day [fruit] оэ fruit easter sunday .оэ Thread: 5 created for msg: easter sun4ay [fruiji fruit , Thread: thread: thread: thread: % Good bye , . 6, created for msg: Good bye [fruit] 5, exited. rc=139424 6, exited. rc=139424 > ,4, exited. rc=139424 1ШО0 лото у л эж ytso-;?л а кэтэн! qx ill п .я. На системной консоли машины fniit при этом появляются следующие сообщения: server:easter sunday server:Good bye server:happy day . 13.4. API потоков выполнения, определенный в стандарте POSIX. 1с в этом разделе речь пойдет об API, который предусмотрен в стандарте POSIX. 1с для основных операций управления потоками. Ниже приведена таблица соответствия API потоков выполнения стандарта POSIX. 1с и фирмы Sun. API потоков выполнения Sun API потоков выполнения POSIX. 1с thr create thr self thr exit thr kill thr join pthread create pthread self pthread exit pthread kill pthreadjoin Чтобы программа могла использовать эти API, в нее должен быть включен заголовок <pthread.h>, в котором объявляются все прототипы многопотоковых функций стандарта POSIX. 1с. Кроме того, если программа управляет приоритетами планирования потоков, необходимо включить и заголовок <sched.h>. Сиетеимое пр 13.4.1. Функция pthread create Прототип функции pthreadcreate выглядит следующим образом: #include <pthread.h> int pthread create (pthread t* tid p, const pthread attr t* attr, void* (*funcp)(void*), void* argp); Эта функция создает новый поток для выполнения функции, адрес которой задан аргументом funcp. Функция, указанная в этом аргументе, должна принимать один входной аргумент типа void* и возвращать данные такого же типа. Фактический аргумент, который передается в функцию funcp в начале выполнения нового потока, указывается в аргументе argp. Идентификатор нового потока возвращается через аргумент tid р. Если этому аргументу присвоено значение NULL, идентификатор не возвращается. Тип данных идентификатора потока - pthreadj. Аргумент attr содержит атрибуты, присваиваемые вновь создаваемому потоку. Значение этого аргумента может быть равно NULL, если новый поток должен использовать атрибуты, принятые в системе по умолчанию, или адресу объекта, содержащего атрибуты. В POSIX. 1с определяется набор API для создания, удаления, запроса и установки атрибутов. Объект, содержащий атрибуты, может быть связан с несколькими потоками, чтобы при каждом обновлении атрибутов сделанные изменения распространялись на все потоки, связанные с этим объектом. Напомним, что для каждого Sun-потока атрибуты задаются индивидуально. Функция pthread attr init создает объект, содержащий атрибуты, а функция pthread attr destroy удаляет такой объект: #include <pthread.h> int pthread attr init( pthread attr t* attr p ); int pthread attr destroy( pthread attr t* attr+p ); Атрибуты объекта, созданного функцией pthread attr init, можно проверить функцией pthread attr get или установить функцией pthread attr set. Ниже перечислены атрибуты, которые могут содержаться в объекте, и соответствующие API для их проверки и установки. Атрибут АР! для проверки АР! для установки Область действия конкуренции Размер стека pthread attr getscope pthread attr getstacksize pthread attr setscope pthread attr setstacksize Аарес стека Состояние отсоединения Правила планирования Параметры планирования pthread attr getstackaddr pthread attr setstackaddr pthread attr getdetachstate pthread attr setdetachstate pthread attr getschedpolicy pthread attr setschedpolicy i pthread attr getschedparam pthread attr setschedparam Bee эти API pthread attr get принимают два аргумента: указатель на объект, содержащий атрибуты, и адрес переменной, в которой должно храниться затребованное значение атрибута. Все API pthread attrjset также принимают два аргумента: указатель на объект и либо новое значение атрибута, либо указатель на переменную, где хранется это новое значение. Область действия конкуренции при гшанировании рассматривалась в разделе 13.2. Возможные значения этого атрибута - PTHREAD SCOPE PROCESS и PTHREAD SCOPE SYSTEM. Состояние отсоединения потока показывает, каким создается поток: отсоединенным или присоединяемым. Возможные значения - PTHREAD CREATE DETACHED или PTHREAD CREATE JOINABLE. Правила планирования потока задают, среди прочего, приоритет потока. Второй аргумент в API pthread attr getschedparam и pthread attr setsched-param - это адрес переменной типа struct sched param. В этой переменной есть целочисленное поле shcedpriority, в котором задается приоритет любого потока, обладающего этим свойством. Наконец, размер и адрес динамического стека вновь создаваемого потока можно устанавливать почти так же, как в аргументах stack size и stackp при вызове функции thr create (см. раздел 13.3.1). Однако для установки этих свойств для одного или нескольких потоков используются API pthread jattr setstacksize и pthread attr setstackaddr. В приведенном ниже примере создается новый отсоединенный и связанный поток с приоритетом 5. Этот поток выполняет функцию doit с аргументом, заданным переменной pint. Идентификатор нового потока присваивается переменной tid, а выделяемый стек имеет стандартный размер: extern void* do it(void* ptr); int *plnt; pthread t tid; pthread attr t attr, *attrPtr = Sattr; struct slied param sched; if (pthread attr init(attrPtr) == -1) { perror( pthread attr init ); attrPtr = 0; else { pthread attr setdetachstate( attrPtr, PTHREAD CREATE DETACH ); pthread attr setscope( attrPtr, PTHREAD SCOPE SYSTEM ); if (pthread attr getschedparam(attrPtr, &sched)==0) { param.sched priority =5; pthread attr setschedparam(attrPtr, ssched); if (pthread create(&tid, &attr, do it, (void*)Splnt)== -1) perror( pthread create ) ; 13.4.2. Функции pthread exit, pthread detach и pthread Join Прототипы функций pthreadjexit, pthreadjdetach и pthread Join приведены нргже: #include <pthread.h> int pthreadjexit ( void* status ); int pthreadjdetach (void* status ); pthreadjoin ( pthread t tid, void** statusp ); И функция pthread exit, и функция pthreadjetach заверщают поток. Функция pthreadjexist может использоваться неотсоединенным потоком, а функция pthread detach применяется отсоединенным потоком. Значение аргумента statusp - адрес статической переменной, которая содержит код возврата заверщающегося потока. Если никакой другой поток не будет использовать код возврата заверщающегося потока, значение этого аргумента можно указать как NULL. Функция pthreadJoin вызывается для ожидания заверщения неотсоеди-ненного потока. Она возвращает код возврата потока, переданный через вызов функции pthreadjexit. В приведенном ниже примере программа ожидает завершения всех неотсоединенных потоков процесса, а затем заверщает текущий поток: status int *rc, rval = 0; thread t tid; if (.pthread join (tid, &rc) cout thread: (int)tid ,exits, rc= (*rc) endl; pthread exit((void*)srval); 13.4.3. Функции pthread sigmask и pthread k4 Прототипы функций pthreadjSigmask и pthread Jill имеют вид: #include <pthread.h> #mclude <signal.h> iUl ni-lTM J 9 t-t* sigsetp, sigset.t* oldsetp ); nt pthreadjl/i ( pthread t tid, int signum );
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |