Семафоры
Добавлено: 09 окт 2011, 23:19
Есть у меня один студент, активно прогуливавший дисциплину "Параллельное программирование". Как результат - ничего не знает из теории и не ориентируется в практике. Зато работает у одного из наших городских провайдеров, немного понимает в C#, в веб-программировании, в ИТ под виндой. На основе всего этого считает, что достоин как минимум трояка по моему предмету. Вот только одна беда - лично я считаю, что даже трояк у меня должен быть заработан, а не поставлен за красивые глазки или некие сторонние достижения. Результат: на экзамене студент получает 2 за незнание предмета. На пересдаче получает 2 за незнание предмета. На комиссии получает 2 за незнание предмета. Заметьте - именно за незнание предмета. Т.е. человек сдает практически пустой листочек и молчит в ответ на вопросы. Ну, думаю, ладно, может он просто базовых положений сформулировать не может, а вот создать набор параллельно-функционирующих и взаимодействующих приложений сумеет. Правда, опыт показывает, что с решением задач, если они не элементарны, у студента тоже все плохо (две недели решал задание одной лабораторной работы). На самой распоследней пересдаче, после очередного пустого листочка в ответ на экзаменационный вопрос, дал ему задачу:
Дано число X. Создать две программы. Запущенные в произвольном кол-ве экземпляры первой программы циклически ожидают ввода строки, в которой подсчитывают кол-во единиц. Экземпляр второй программы ожидает, пока суммарное количество введенных единиц во всех экземплярах первой программы не достигнет или не превысит значения X. После чего сигнализирует об этом факте. Коммуникация программ друг с другом - только с помощью системных семафоров или событий. Во время работы пользовательский ввод программ не блокируется. Порядок запуска программ - произвольный.
Язык и ОС разрешил использовать любой. Студент выбрал C# и Windows. Отвел ему на решение одну пару. Не решил. Дал еще две пары. Не решил. Разрешил решать до конца дня. Не решил. Ну, думаю, ладно - детский сад штаны на лямках, отпущу до понедельника (дело было в пятницу), может ему кто поможет. Сегодня пришло в голову - может сложную задачку дал? Попробовал решить сам. Оказалось не сложно, но интересно. 15 минут на решение, 30 на отладку (подзабыл о персистентости именованных posix-семафоров). Вот что вышло:
Число X содержится в текстовом файле x.txt
Первая программа:
Вторая программа:
В случае аварийного останова первой программы захваченный семафор не освобождается, что, естественно, скажется на корректности работы. В принципе, устойчивости к аварийным ситуациям от программы не требовалось, однако для подчистки "хвостов" можно использовать, например, следующую программу:
Другой вариант заключается в организации реакции на сигналы завершения, но было уже лень это делать, ибо сути программы обработка сигналов не изменит, да и спать уже хочется . Посмотрим, что мне завтра (т.е. уже сегодня) принесет студент. Подозреваю, что отговорки, но как знать...
Дано число X. Создать две программы. Запущенные в произвольном кол-ве экземпляры первой программы циклически ожидают ввода строки, в которой подсчитывают кол-во единиц. Экземпляр второй программы ожидает, пока суммарное количество введенных единиц во всех экземплярах первой программы не достигнет или не превысит значения X. После чего сигнализирует об этом факте. Коммуникация программ друг с другом - только с помощью системных семафоров или событий. Во время работы пользовательский ввод программ не блокируется. Порядок запуска программ - произвольный.
Язык и ОС разрешил использовать любой. Студент выбрал C# и Windows. Отвел ему на решение одну пару. Не решил. Дал еще две пары. Не решил. Разрешил решать до конца дня. Не решил. Ну, думаю, ладно - детский сад штаны на лямках, отпущу до понедельника (дело было в пятницу), может ему кто поможет. Сегодня пришло в голову - может сложную задачку дал? Попробовал решить сам. Оказалось не сложно, но интересно. 15 минут на решение, 30 на отладку (подзабыл о персистентости именованных posix-семафоров). Вот что вышло:
Число X содержится в текстовом файле x.txt
Первая программа:
Подсветка синтаксиса языка pascal
{$mode objfpc}
uses libc;
var t:text; x:integer;
s:string;
curr_set:integer=0;
var sem:psem_t;
procedure am(cnt:integer);
var value,res:longint;
begin
sem_getvalue(sem,@value);
writeln('Захватываем семафорчик в кол-ве ',cnt,' блокировок. На семафоре осталось ~ ',value);
while cnt<>0 do begin
res:=sem_trywait(sem);
if res<>0 then begin
sem_getvalue(sem,@value);
writeln('Не срослось захватить все, конкуренты помешали.');
writeln('Незахватилось ' ,cnt,' блокировок. На семафоре осталось ~ ',value);
break;
end;
inc(curr_set);
dec(cnt);
end;
sem_getvalue(sem,@value);
writeln('Захватили семафорчик в кол-ве ',curr_set,' блокировок. На семафоре осталось ~ ',value);
end;
procedure tfu();
var value:longint;
begin
sem_getvalue(sem,@value);
writeln('Отдаем блокировки в кол-ве ',curr_set,' блокировок. На семафоре сейчас ~ ',value);
while curr_set<>0 do begin
sem_post(sem);
dec(curr_set);
end;
sem_getvalue(sem,@value);
writeln('Отдали блокировки. На семафоре осталось ~ ',value);
end;
function cnt(s:string):integer;
var i:integer;
begin result:=0; for i:=1 to length(s) do if s[i]='1' then inc(result); end;
begin
assign(t,'x.txt');reset(t);readln(t,x);close(t);
sem:=sem_open('test',O_CREAT,511,x);
while true do begin
readln(s); if s='' then break;
tfu();
am(cnt(s));
end;
tfu();
sem_close(sem);
//sem_unlink('test');
end.
uses libc;
var t:text; x:integer;
s:string;
curr_set:integer=0;
var sem:psem_t;
procedure am(cnt:integer);
var value,res:longint;
begin
sem_getvalue(sem,@value);
writeln('Захватываем семафорчик в кол-ве ',cnt,' блокировок. На семафоре осталось ~ ',value);
while cnt<>0 do begin
res:=sem_trywait(sem);
if res<>0 then begin
sem_getvalue(sem,@value);
writeln('Не срослось захватить все, конкуренты помешали.');
writeln('Незахватилось ' ,cnt,' блокировок. На семафоре осталось ~ ',value);
break;
end;
inc(curr_set);
dec(cnt);
end;
sem_getvalue(sem,@value);
writeln('Захватили семафорчик в кол-ве ',curr_set,' блокировок. На семафоре осталось ~ ',value);
end;
procedure tfu();
var value:longint;
begin
sem_getvalue(sem,@value);
writeln('Отдаем блокировки в кол-ве ',curr_set,' блокировок. На семафоре сейчас ~ ',value);
while curr_set<>0 do begin
sem_post(sem);
dec(curr_set);
end;
sem_getvalue(sem,@value);
writeln('Отдали блокировки. На семафоре осталось ~ ',value);
end;
function cnt(s:string):integer;
var i:integer;
begin result:=0; for i:=1 to length(s) do if s[i]='1' then inc(result); end;
begin
assign(t,'x.txt');reset(t);readln(t,x);close(t);
sem:=sem_open('test',O_CREAT,511,x);
while true do begin
readln(s); if s='' then break;
tfu();
am(cnt(s));
end;
tfu();
sem_close(sem);
//sem_unlink('test');
end.
Вторая программа:
Подсветка синтаксиса языка pascal
{$mode objfpc}
uses cthreads,sysutils,libc,classes;
type
tsemthread=class(tthread)
procedure execute; override;
end;
procedure tsemthread.execute;
var sem:psem_t;
value:longint;
begin
repeat
if terminated then exit;
sem:=sem_open('test',0,511,1);
sleep(1);
until sem<>nil;
while true do begin
if terminated then break;
sem_getvalue(sem,@value);
if value=0 then write('YES!!!!');
sleep(1);
end;
sem_close(sem);
end;
var
t:tsemthread;
s:string;
begin
t:=tsemthread.create(false);
while true do begin
readln(s); if s='' then break;
writeln(s);
end;
t.terminate;
t.waitfor;
t.destroy;
end.
uses cthreads,sysutils,libc,classes;
type
tsemthread=class(tthread)
procedure execute; override;
end;
procedure tsemthread.execute;
var sem:psem_t;
value:longint;
begin
repeat
if terminated then exit;
sem:=sem_open('test',0,511,1);
sleep(1);
until sem<>nil;
while true do begin
if terminated then break;
sem_getvalue(sem,@value);
if value=0 then write('YES!!!!');
sleep(1);
end;
sem_close(sem);
end;
var
t:tsemthread;
s:string;
begin
t:=tsemthread.create(false);
while true do begin
readln(s); if s='' then break;
writeln(s);
end;
t.terminate;
t.waitfor;
t.destroy;
end.
В случае аварийного останова первой программы захваченный семафор не освобождается, что, естественно, скажется на корректности работы. В принципе, устойчивости к аварийным ситуациям от программы не требовалось, однако для подчистки "хвостов" можно использовать, например, следующую программу:
Подсветка синтаксиса языка pascal
{$mode objfpc}
uses libc;
begin
sem_unlink('test');
end.
uses libc;
begin
sem_unlink('test');
end.
Другой вариант заключается в организации реакции на сигналы завершения, но было уже лень это делать, ибо сути программы обработка сигналов не изменит, да и спать уже хочется . Посмотрим, что мне завтра (т.е. уже сегодня) принесет студент. Подозреваю, что отговорки, но как знать...