Конкурентно Програмиране



Дата25.07.2016
Размер205.98 Kb.
Конкурентно Програмиране




Конструкции от високо ниво, основани на предаване на съобщения

Remote Procedure Call, Rendezvous

Механизмите Remote Procedure Call и Rendezvous комбинират аспекти на двата подхода за комуникация и синхронизация – на базата на обща памет и на основата на предаване на съобщения. Те обобщават идеята за активен монитор и имат следните свойства:



  • конструкции от високо ниво;

  • двупосочна комуникация;

  • синхронна и асинхронна комуникация;

  • избирателна комуникация;

  • приложими както при системи с обща памет, така и на разпределени системи;

  • капсулация на данните.

I. Remote Procedure Call (RPC)


RPC механизмът прилича на механизма за извикване на процедура, с тази разлика, че виканата процедура може да се изпълни на друг процесор. В процес, изпълняващ се на един процесор, може да се направи обръщение към операция, изпълнявана от друг процес на отдалечен процесор.
RPC използва добре познатите синтаксис и семантика на обръщение към процедура, като осигурява различна реализация. За изпълнение на тялото на извиканата процедура динамично се поражда нов процес, който завършва след като това изпълнение приключи. По този начин изпълнението на една и съща процедура при различни обръщения се осъществява от различни процеси.
RPC създава двупосочен канал за комуникация между викащия процес и процеса, изпълняващ виканата операция – в началото се предават параметрите за изпълнение на операцията, а на края се връща резултата от нейното изпълнение.
При RPC нормално се използва синхронна комуникация, т.е. процесът, който прави обръщение се забавя докато получи обратно резултата. Възможно е обаче използване на асинхронна комуникация чрез указване на отдалечената операция в примитива send.
RPC механизмът може да се ползва както при системи с обща памет, така и при разпределени системи. Ако при RPC няма предаване на данни, то той реализира само синхронизация.
За реализиране на механизма на RPC е необходимо изпълнителят да се идентифицира и да се изпраща съответната информация до отдалечената машина.
Реализация на RPC



Основни етапи при реализация на RPC:
А. Аргументите на RPC се пакетират в съобщение. Генерира се RPC идентификатор на обръщението, с цел коректното връщане на отговор към процеса, изпълняващ обръщението. Съобщението се изпраща по мрежата посредством протокола от ниско ниво.
В. Аргументите се извличат от съобщението и се преобразуват във вид, подходящ за изпълнение на локалното обръщение.
С. Създава се нов процес, който изпълнява съответната процедура.
D. Изходните резултати се пакетират в съобщение, което се изпраща по мрежата посредством протокола от ниско ниво.
Е. Резултатът се извлича от съобщението и се предава посредством RPC идентификатора на процеса, направил обръщението.
RPC механизмът е специално предназначен да обслужва модела Client/Server. В модела Client/Server има строго определена схема на взаимодействие между процесите:
Client: send – receive

Server: receive – send


Клиентът вика услуга /процедура/, която се изпълнява от сървера /евентуално на отдалечена машина/.
В клиента:

call service (value_args; result_args)


В сървера:

remote procedure service(value_param; result_param)


Така декларираната процедура се реализира като процес, което може да стане по два начина:

  • като единствен процес, който циклично предлага услугата;

  • като за всяко ново обръщение се поражда нов процес. Това пък поставя въпроса за интерфериране на породените процеси и тяхната синхронизация.

Интегриране на средствата, реализращи RPC механизма в езика, освобождава програмиста от детайлите на реализация на отдалечения достъп. При компилиране на обръщението в клиентската програма, в нея се включва т.н. stub, който служи като представител на кода на отдалечената процедура. Когато при изпълнение на програмата се направи обръщението към отдалечената процедура, този stub получава заявката за изпълнение и я предава на runtime системата на локалния компютър. Тя от своя страна разполага с адреса на отдалечения компютър и изпраща по мрежата съобщение към сървера за изпълнение на исканата операция. Аналогично, сърверът включва runtime система и skeleton, съответстващ на отдалечената процедура, така че връщането на резултатите към клиентската програма става по същия начин.

Ако няма предаване на данни в двете посоки, то чрез RPC се прави само синхронизация.




II. Extended Rendezvous

При ER изпълнението в основни линии е като при RPC. Клиентът изпраща съобщение, съдържащо заявка за обръботка и чака, докато то бъде прието, обработено от сървера и изпратено обратно съобщение.


Разликата е основно в две насоки:

  • изпълнението се осъществява от съществуващ процес-сервер;

  • от синтактична гледна точка – се описва със съответни конструкции, което дава възможност те да се вграждат на произволно място в текста на процеса, или да се влагат.


Клиент: Конструкция, която прилича на обръщение към процедура или функция, в зависимост от езика. Аналогично на случая RPC, обръщението може да бъде обслужено на друг процесор.
Сървер: Оператор accept, който реализира избирателна комуникация /guarded commаnd на Dijkstra/, т.е. предоставя средство за изразяване на недетерминизъм.
accept service(value_param; result_param)

………..


end;

Съществената разлика е, че отделните сърверни операции се изпълняват в режим на взаимно изключване, тъй като всички те се реализират от един процес.


Предимства на ER:

  • Сърверът може да избере кога да обслужи клиента - accept операторите могат да се редуват или да се влагат;

  • Един сървер може да предлага различни услуги чрез различни accept оператори;

  • Accept може да се комбинира с избирателна комуникация, така сърверът може да чака и избира коя заявка да изпълни.

  • Може да се вгради механизъм, който кара сървера да приема заявка въз основа на минимизация на функция от параметрите й.

По семантика RPC и ER трябва да свърши когато сърверът обслужи заявката и върне съобщение на клиенат. Но при грешка може да се окаже, че клиентът е блокиран, защото:



  • съобщението към сървера не е получено;

  • сърверът е аварирал при изпълнение;

  • обратното съобщение е изгубено.

Необходимо е да се предвиди реакция на тези изключителни ситуации.

Concurrent C/C++




Механизмът за комуникация и синхронизация в Concurrent C/C++ е транзакцията, която по същество е extended rendezvous. Процесите съдържат точки за комуникация и синхронизация /транзакции/, които могат да се викат от други процеси, като синтаксисът на обръщението е като този на викане на функция /метод/. Синхронизацията на процеса, правещ обръщение към транзакция и процеса, приемащ транзакцията, става при осъществяване на rendezvous. Тогава след предаване на входните параметри, ако има такива, викащият процес се блокира докато виканият изпълнява тялото на транзакцията. При край на изпълнението към викащия процес се предават изходните параметри, с което rendezvous завършва и двата процеса продължават асинхронната си работа.


Така схематично изглежда кодът на процес – сървер.
process spec service()

{

trans result get(int urgency_level, data d);



}
process body service()

{

for (;;)



{

accept get(urgency_level, d) by (-urgency_level)

{ perform request }

}

}



Задача Производител – Потребител с краен буфер

process spec producer(process buffer);

process spec consumer(process buffer);
process body producer(buf) {

int c;


do {

buf.put(c=getchar());

} while (c!=EOF);

}
process body consumer(buf) {

int c;

while((c=buf.get())!=EOF)



putchar(islower(c) ? toupper : c);

}

process spec buffer(int max) {



trans void put(int c);

trans int get();

};
process body buffer(max)

{

int *buf; /*circular buffer of max bytes*/



int n = 0; /*number of characters in buffer*/

int in = 0; /*index of next available empty slot*/

int out = 0; /*index of next available character*/

char *malloc();

void free();

if ((buf = (int *) malloc(max*sizeof(int)))==NULL){

fprintf(stderr, "error, no more storage\n");

exit(1);


}

for (;;)


select {

(n < max):

accept put(c) buf[in] = c;

in = (in + 1) % max;

n++;

or

(n > 0):



accept get() return buf[out];

if (buf[out] == EOF break;

out = (out + 1) % max;

n--;


}

free((char *) buf);

}
main() {

process buffer buf;

buf=create buffer(BUFFER_SIZE);

create consumer(buf);

create consumer(buf);

}


process spec disk_scheduler()

{

trans void request(cylinder cyl, read_write rw, buffer buf);



};
#define ABS(x) ((x)>0?(x):-(x))

process body disk_scheduler()

{

int position = 1;



for (;;) {

accept request(cyl, rw, buf) by ABS(cyl-position) {

position = cyl;

switch (rw) {

case READ: start disk read; break;

case WRITE: start disk write; break;

}

wait for disk operation to complete;

}

}



}
process spec lock_mngr()

{

trans void get_lock(lockid id);



trans void release_lock(lockid id);

};
process body lock_mngr() {

lockid id;

for (;;)


select {

accept get_lock(xid) suchthat (unlocked(xid))

{ id = xid; }

lock(id);

or

accept release_lock(xid)



{ id = xid; }

unlock(id);

}

}

/*unlocked(xid) returns true if item xid is unlocked*/



/*lock(xid) locks item xid, unlock(xid) unlocks item xid*/

Език Ada
Средството на езика Ada за описание на процеси се нарича задача /task/.
Подобно на пакетите задачата има спецификация и тяло, но не е компилационна единица.

Подобно на процедура задачата има декларативна и изпълнима част, но обръщението към нея е различно.

Подобно на структура данни задачата има тип и се създава при деклариране на обект от този тип.
Допуска се декларирането на единична задача от анонимен тип или на тип-задача. В последния случай впоследствие могат да се създадат произволен брой обекти от този тип.
task_type_declaration ::=

task type defining_identifier [known_discriminant_part] [is task_definition];


single_task_declaration ::=

task defining_identifier [is task_definition];


task_definition ::=

{task_item}

[ private

{task_item}]

end [task_identifier]
task_item ::= entry_declaration | representation_clause
task_body ::=

task body defining_identifier is

declarative_part

begin


handled_sequence_of_statements

end [task_identifier];


Обработката на дефиницията на тип – задача има за последствие това, че след нея могат да бъдат успешно активирани обекти от този тип.
Активирането на съответния обект води до начало на изпълнение на кода от тялото на задачата.
Типът задача е ограничен, което значи, че за него не са допустими никакви операции, включително присвояване и сравнение за равенство. Ако едно приложение има нужда да запазва или предава идентификатор на задача, то може да стори това като използва указателен тип към съответния тип-задача.
Примерни декларации на типове – задачи:

task type Server is

entry Next_Work_Item(WI : in Work_Item);

entry Shut_Down;

end Server;

task type Keyboard_Driver(ID : Keyboard_ID := New_ID) is

entry Read (C : out Character);

entry Write(C : in Character);

end Keyboard_Driver;
Примерни декларации на задачи от анонимен тип:
task Controller is

entry Request(Level)(D : Item); -- a family of entries

end Controller;
task Parser is

entry Next_Lexeme(L : in Lexical_Element);

entry Next_Action(A : out Parser_Action);

end;
task User; -- has no entries

Примери на обекти – задачи:
Agent : Server;

Teletype : Keyboard_Driver(TTY_ID);

Pool : array(1 .. 10) of Keyboard_Driver;
Пример за тип – указател към задача:
type Keyboard is access Keyboard_Driver;

Terminal : Keyboard := new Keyboard_Driver(Term_ID);


Процесите в Ada се поражда статично или динамично.
1. Статично: Декларира се тип задача и обект от него. При обработка на декларацията на обекта се алокира памет, създава се дескриптор на процеса и вече други процеси могат да се обръщат към него без това да предизвика грешка. Следва активирането, при което процесът е готов да участва в планирането и да получава процесора. Това става в блока, в който е даклариран, преди началото на неговите изпълними оператори. Ако една задача стартира активирането на други задачи, тя се блокира докато това активиране завърши, а след това продължава да работи конкурентно с тях.
procedure main is

task type T is

……………………

T1, T2: T;

begin

-- activated T1, T2, main

statement1

…………..

statementn



end;
procedure P is

A, B : Server; -- elaborate the task objects A, B

C : Server; -- elaborate the task object C

begin


-- the tasks A, B, C are activated together

...


end;
2. Динамично: При обработка на алокатор става създаване на процеса и веднага неговото активиране – след което се връща указател към него.
.................................

task type T is……….

type P is access T;

New_Task: P;

declare

……………………


begin

New_Task=new T; -- creation + activation

…………..

end;


..................................
Ако няколко задачи се активират едновременно, то изпълнението на коя да е от тях не е необходимо да чака края на активацията на останалите.
Прекратяване на задачата:
Environment task – винаги има неявно една задача, която изпълнява главната програма.

Всяка задача има master:



  • при статично пораждане – блокът, в който е декларацията на обекта;

  • при динамично пораждане – блокът, в който е декларацията на типа и съответно всеки блок, който го съдържа.

Така задачата зависи от всяка задача, която изпълнява master-a. Ако една задача, която има зависими задачи, достигне до състояние completed, то тя се блокира докато всички зависещи задачи достигнат до състояние terminated.



Комуникация и синхронизация на процесите

Пример за асинхронно изпълнение на две задачи.


WITH Ada.Text_IO;

PROCEDURE Two_Tasks IS


TASK TYPE SimpleTask (Message: Character; HowMany: Positive);

TASK BODY SimpleTask IS

BEGIN -- SimpleTask

FOR Count IN 1..HowMany LOOP

Ada.Text_IO.Put(Item => "Hello from Task " & Message);

Ada.Text_IO.New_Line;

END LOOP; 

END SimpleTask;

 

Task_A: SimpleTask(Message => 'A', HowMany => 5);



Task_B: SimpleTask(Message => 'B', HowMany => 7);

 

BEGIN -- Two_Tasks



  NULL;

END Two_Tasks;



В езика Ada се използват два механизъма за синхронизация и комуникация:


- Rendezvous /активен монитор/ – основан на предаване на съобщения;

- Protected Object /пасивен монитор/ - основан на използване на обща памет.



Rendezvous

При синхронизация на задачи се използва механизма rendezvous само ако трябва да се синхронизират актуални процеси, т.е. да се зададе зависещо от времето подреждане на събитията или обмен на данни.


Взаимодействието rendezvous между две задачи се състои в синхронизиране на процесите и установяване на двупосочен канал за комуникация между тях. След като двата процеса се синхронизират процесът, искащ rendezvous /клиентът/ издава заявката като изпраща входните параметри и се блокира. Процесът, обслужващ заявката /сърверът/, продължава с изпълнение на действията по изпълнение на заявката /тялото на rendezvous/ след което предава параметри в обратна посока. Следва разблокиране на клиента и приемане на параметрите с което rendezvous е завършило и двата процеса продължават асинхронната си работа. Постигане само на синхронизация се получава когато няма предаване на параметри и тялото на rendezvous е празно.
В сървера:

  • в спецификацията на задачата се задават имената и параметрите на входните точки /entry/, по една за всяка обслужвана от сървера заявка;

entry_declaration ::=

entry defining_identifier [(discrete_subtype_definition)]

parameter_profile;




  • в тялото на задачата – оператор accept, обслужващ дадена входна точка.

accept_statement ::=

accept entry_direct_name [(entry_index)] parameter_profile [do

handled_sequence_of_statements

end [entry_identifier]];
Примери за декларации на входни точки:
entry Read(V : out Item);

entry Seize;

entry Request(Level)(D : Item); -- a family of entries
Примери за accept оператори:
accept Shut_Down;
accept Read(V : out Item) do

V := Local_Item;

end Read;
accept Request(Low)(D : Item) do

...


end Request;

В клиента – обръщение към входна точка:


entry_call_statement ::= entry_name [actual_parameter_part];
Една входна точка /entry/ има две състояния:

  • отворена – ако съответният процес е готов веднага да осъществи комуникация, т.е. да приеме заявка за обслужването й;

  • затворена – в противен случай.

Ако входната точка е затворена обръщението се запазва в опашка, докато настъпи моментът, в който може да бъде обслужено. С всяка входна точка е асоциирана отделна /логическа/ опашка от необслужени заявки.


Примери за обръщения към входни точки:
Agent.Shut_Down;

Parser.Next_Lexeme(E);

Pool(5).Read(Next_Char);

Controller.Request(Low)(Some_Item);

Flags(3).Seize;
Примери за синхронизация на задачи:
task Task_1 is task Task_2;

entry Syncronize;

End Task_1;
task body Task_1 is task body Task_2 is

begin begin

………….. ………..

accept Syncronize; Task_1.Syncronize;

………….. ………..

end Task_1; end Task_2;


WITH Ada.Text_IO;

PROCEDURE StartTaskСontrol IS


TASK TYPE SimpleTask (Message: Character; HowMany: Positive) is

ENTRY StartTask;

END SimpleTask;
TASK BODY SimpleTask IS

BEGIN – SimpleTask

accept StartTask;

………………………..

END SimpleTask;

 

Task_A: SimpleTask(Message => ‘A’, HowMany => 5);



Task_B: SimpleTask(Message => ‘B’, HowMany => 7);

  Task_C: SimpleTask(Message => ‘C’, HowMany => 11);


BEGIN – StartTaskControl

  Task_A.StartTask;

Task_B.StartTask;

Task_C.StartTask;

END StartTasksControl;
Примери за влагане на оператори accept:
Rendezvous на три задачи:
task body T1 is

begin


accept From_T2 do

accept From_T3 do

end;

end;


end T1;
Внимание!!! Опасност за Deadlock!
Task A is Task B is

entry AA; entry BB;

end A; end B;

task body A is task body B is

begin begin

B.BB; A.AA;

accept AA; accept BB;

end A; end B;


Влагане на оператори accept:
task A;
task B is

entry Service (Kind: Service_Kind; Result: out Result_Type);

entry S_Kind(Service_Kind) (R: Result_Type);

end B;
task body A is

…………

begin


…………

B.Service(K1, Res);

…………

end A;
task body B is



…………

begin


loop

accept Service (Kind: Service_Kind; Result: out Result_Type) do

accept S_Kind(Kind) (R: Result_Type) do

Result:=R;

end S_Kind;

end Service;

……………..

end loop;



end B;
Оператор delay
Операторът се използва за указание към процеса да бъде забавен и има две форми:

  • указване на момента, в който изпълнението може да продължи;

  • указване на период на забавяне спрямо текущия момент.

delay 3.0; -- delay 3.0 seconds


declare

use Ada.Calendar;

Next_Time : Time := Clock + Period;


  1. Period is a global constant of type Duration

begin

loop -- repeated every Period seconds

delay until Next_Time;

... – perform some actions

Next_Time := Next_Time + Period;

end loop;

end;
Оператор requeue
Изпълнението на тялото на rendezvous може да приключи по три начина:


  • при изчерпване на операторите;

  • при достигане до оператор return;

  • при достигане до оператор requeue.

В последния случай заявка, която се изпълнява в момента, се прехвърля в опашката на указаната входна точка /в частност може същата/.
requeue_statement ::= requeue entry_name [with abort];
Примери за оператори requeue
requeue Request(Medium) with abort;

-- requeue on a member of an entry family of the current task
requeue Flags(I).Seize;

-- requeue on an entry of an array component
Избирателна комуникация – оператор select
Операторът select реализира командата if…fi на Dijkstra за изразяване на недетерминизма. Select дава възможност за:

  • приемане на обръщение за rendezvous в различни входни точки от различни задачи-клиенти по недетерминиран начин;

  • задаване на време за чакане на заявка за rendezvous;

  • предприемане на алтернативни действия при липса на заявка за rendezvous;

  • указване на готовност за прекратяване на работа.

Select_statement ::=

selective_accept

| timed_entry_call

| conditional_entry_call

| asynchronous_select



Selective Accept – избирателна комуникация

Тази форма на оператора позволява едновременно да се чака и да се избира между различни алтернативи, зависещи от условия, свързани с всяка от тях.


Selective_accept ::=

select


[guard]

select_alternative

{ or

[guard]


select_alternative }

[ else


sequence_of_statements ]

end select;


guard ::= when condition =>
select_alternative ::=

accept_alternative

| delay_alternative

| terminate_alternative


accept_alternative ::=

accept_statement [sequence_of_statements]


delay_alternative ::=

delay_statement [sequence_of_statements]


terminate_alternative ::= terminate;

Семантика на оператор select


  • Изчисляват се гардовете на всички алтернативи и се формира множество на отворените алтернативи. Ако няма такива се изпълняват действията, указани в else клаузата, иначе възниква Programm Error;

  • Ако има чакащи задачи в опашките на отворените алтернативи, от някоя опашка се избира първата чакаща задача и се реализира rendezvous;

  • Ако опашките са празни, задачата се блокира докато друга задача поиска rendezvous за входна точка с отворена алтернатива. Докато задачата е блокирана гардовете не се преизчисляват;

  • След rendezvous се изпълняват операторите до следващата алтернатива.


Delay алтернатива – избира се когато има отворена accept алтернатива, но няма чакащи, или няма отворена accept алтернатива. Избира се алтернативата с най-малко време за чакане, ако преди то да изтече се получи заявка за rendezvous на отворена accept алтернатива, то rendezvous се осъществява, иначе се изпълняват операторите в delay клаузата.
Task body T is

Current_Work_Item : Work_Item;

begin

loop


select

accept Sensor_1 do

………………

end;


or

accept Sensor_2 do

……………….

End;


or

delay 0.1;

Raise_Alarm;

end select;

end loop;

end T;
Terminate алтернатива – избира се когато:



  • няма чакащи заявки на входните точки на задачата;

  • няма зависещи от нея задачи;

  • master на задачата е в състояние completed и всички негови наследници са в състояние terminated или чакат на terminate алтернатива.

Task Server is

entry Next_Work_Item(WI : in Work_Item);

entry Shut_Down;

end Server;
task body Server is

Current_Work_Item : Work_Item;

begin

loop


select

accept Next_Work_Item(WI : in Work_Item) do

Current_Work_Item := WI;

end;


Process_Work_Item(Current_Work_Item);

or

accept Shut_Down;



exit; -- Premature shut down requested

or

terminate; -- Normal shutdown at end of scope



end select;

end loop;

end Server;
Else клауза – тя се избира и указаните в нея оператори се изпълнават ако никоя accept алтернатива не може да доведе до незабавно осъществяване на rendezvous.

Task DISK_SCHEDULER is

entry REQUEST(CYLINDER) (RW: READ_WRITE; B: BUFFER);

end DISK_SCHEDULER;


task body DISK_SCHEDULER is

I: CYLINDER; CYL: CYLINDER := CYLINDER’FIRST;

STEP: INTEGER := 1;

begin


loop

for I in CYLINDER loop

select

accept REQUEST(CYL) (RW: READWRITE; B: BUFFER) do



start disk operation;

wait for disk operation to complete;

end REQUEST;

else

null;


end select;

CYL := CYL + STEP;

end loop;

STEP := –STEP;

end loop;

end DISK_SCHEDULER;


В един оператор select може да има:

  • terminate алтернатива;

  • или няколко delay алтернативи;

  • или else клауза.

Тези три възможности са взаимно изключващи се.

Timed Entry Callтова е извикване, което процесът-клиент прави, и което се канцелира, ако не бъде обслужено в указаното време.

Timed_entry_call ::=

select

entry_call_alternative



or

delay_alternative

end select;

Пример:


select

Controller.Request(Medium)(Some_Item);

or

delay 45.0;



  1. controller too busy, try something else

end select;

Conditional Entry Call – това е извикване, което процесът-клиент прави, и което се канцелира, ако не бъде веднага обслужено.

Conditional_entry_call ::=

select

entry_call_alternative



else

sequence_of_statements

end select;

Примери:

procedure Spin(R : in Resource) is

begin

loop


select

R.Seize;


return;

else


null; -- busy waiting

end select;

end loop;

end;
Пример за използване на оператор select за реализиране на недетерминиран избор на следваща заявка за използване на променливата Var в режим на взаимно изключване.


Task Access_Control is

entry Add(N: Integer);

      entry Subtract(N: Integer);

entry Value(N: out Integer);

end;
task body Access_Control is

      Var: Integer := 0;

begin

loop


select

accept Add(N: in Integer) do

          Var :=Var+N;

         end Add;

or

accept Subtract(N: Integer) do



Var :=Var+N;

    end Subtract;

or

accept Value(N: out Integer) do



N:=Var;

    end Value;

end select;

end loop;

end Access_Control;
Производител–Потребител с краен буфер, реализиран като отделна задача
task Producer;
task body Producer is

Char : Character;

begin

loop


... -- produce the next character Char

Buffer.Write(Char);

exit when Char = ASCII.EOT;

end loop;

end Producer;
task Consumer;
task body Consumer is

Char : Character;

begin

loop


Buffer.Read(Char);

exit when Char = ASCII.EOT;

... -- consume the character Char

end loop;

end Consumer;
task Bounded_Buffer is

entry Put(X: in Item);

      entry Get(X: out Item);
end;
task body Bounded_Buffer is

      A: Item_Array(1 .. Max);

      I, J: Integer range 1 .. Max := 1;

      Count: Integer range 0 .. Max := 0;

Begin
loop

select


      when Count < Max =>

accept Put(X: in Item) do

          A(I) := X;

         end Put;

I := I mod Max + 1;

Count := Count + 1;

or

      when Count > 0 =>



accept Get(X: out Item) do

         X := A(J);

      end Get;

J := J mod Max + 1;

Count := Count – 1;

end select;

end loop;

end Bounded_Buffer;


Приоритети на задачите
Рragma Priority (N);
Това е указание /незадължително/ за компилатора. Приоритетът засяга само планирането на задачите при работа, а не реда, в който постъпват и се обработват на входните точки.

Приоритет на задачите може да бъде изкуствено симулиран.


Type Priority is (Low, Medium, High);

task Server is

entry Request(Priority) (…);

end Server;


task body Server is

begin


loop

select


accept Request(High)(…)….;

or

when Request(High)’Count=0 =>



accept Request(Medium)(…)….;

or


when Request(High)’Count=0 and Request(High)’Count=0 =>

accept Request(Low)(…)….;

end select;

end loop;

end Server;


Конкурентно програмиране 2005




База данных защищена авторским правом ©obuch.info 2016
отнасят до администрацията

    Начална страница