Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лаб. 4 ФЛП

.docx
Скачиваний:
0
Добавлен:
29.05.2025
Размер:
334.9 Кб
Скачать

Лабораторная работа 4

:- use_module(library(process)).

%ring(3,3,0).

%ring(5,4,1).

ring(N, M, Count) :-

process_id(MainPID),

format("Текущий процесс <~w>~n", [MainPID]),

format("=== Круг 1 ===~n"),

create_processes(N, N, Count, MainPID, ProcessList),

start_rounds(2, M, Count, ProcessList).

% Создание процессов и сохранение их PID в список

create_processes(_, 0, _, _, []) :- !.

create_processes(N, NN, Count, PrevPID, [PID|Rest]) :-

process_create(path(cmd), ['/c', 'exit'], [process(PID)]),

format("Создан процесс <~w>~n", [PID]),

(N =:= NN -> NewCount is Count ; ((N - 1) > NN -> NewCount is Count ; NewCount is Count + 1)),

%(N > NN -> NewCount is Count ; NewCount is Count),

format("<~w> получил Count=~w от <~w>~n", [PID, NewCount, PrevPID]),

process_wait(PID, _),

N1 is NN - 1,

create_processes(N, N1, NewCount, PID, Rest).

% Круги передачи (со 2-го по M-й)

start_rounds(CurrentRound, M, _, _) :-

CurrentRound > M,

%format("Все ~w кругов передачи завершены.~n", [M]),

!.

start_rounds(CurrentRound, M, Count, ProcessList) :-

format("=== Круг ~w ===~n", [CurrentRound]),

last_process(ProcessList, LastPID),

(CurrentRound =:= 2 -> Count1 is Count + 2; Count1 is Count + 1),

emulate_processes(ProcessList, Count1, LastPID, CurrentRound, M),

NextRound is CurrentRound + 1,

start_rounds(NextRound, M, Count1, ProcessList).

% Эмуляция передачи с увеличением Count

emulate_processes([], _, _, _, _) :- !.

emulate_processes([PID|Rest], Count, PrevPID, CurrentRound, M) :-

%NewCount is Count + 1,

format("<~w> получил Count=~w от <~w>~n", [PID, Count, PrevPID]),

(CurrentRound =:= M ->

format("Процесс <~w> завершился~n", [PID])

; true

),

emulate_processes(Rest, Count, PID, CurrentRound, M).

% Нахождение последнего элемента списка

last_process([X], X) :- !.

last_process([_|T], Last) :- last_process(T, Last).

:- module(parent_children, [start/1, send_to_child/2, stop/0]).

:- use_module(library(thread)).

:- dynamic child_pid/1.

% Запуск родительского процесса с N дочерними процессами

start(N) :-

retractall(child_pid(_)), % Удаляем старые идентификаторы дочерних процессов

spawn_children(N), % Создаем дочерние процессы

format('Parent started with ~d children.~n', [N]).

% Создание дочерних процессов

spawn_children(0) :-

!.

spawn_children(N) :-

N > 0,

thread_create(child_process(N), ChildID, [detached(true)]), % Создаем новый процесс

assertz(child_pid(ChildID)), % Сохраняем идентификатор дочернего процесса

N1 is N - 1,

spawn_children(N1). % Рекурсивно создаем оставшиеся процессы

% Отправка сообщения дочернему процессу

send_to_child(I, Msg) :-

findall(ChildID, child_pid(ChildID), ChildIDs),

length(ChildIDs, Length),

( I =< Length

-> nth1(I, ChildIDs, ChildID),

( thread_property(ChildID, status(running))

-> thread_send_message(ChildID, Msg),

format('Sent message to child ~d: ~w~n', [I, Msg])

; format('Child ~d is not running, removing from list.~n', [I]),

retract(child_pid(ChildID)) % Удаляем идентификатор, если поток не запущен

)

; format('Child ~d does not exist.~n', [I])

).

% Остановка всех дочерних процессов

stop_children :-

findall(ChildID, child_pid(ChildID), ChildIDs),

forall(member(ChildID, ChildIDs),

( thread_property(ChildID, status(running))

-> thread_send_message(ChildID, stop) % Отправка сообщения остановки

; format('Child thread ~w does not exist or is not running, removing from list.~n', [ChildID]),

retract(child_pid(ChildID)) % Удаляем идентификатор, если поток не запущен

)),

retractall(child_pid(_)), % Обнуляем массив child_pid

format('All children stopped and child_pid cleared.~n').

% Процесс дочернего потока

child_process(I) :-

format('Child ~d started.~n', [I]),

child_loop(I). % Запуск цикла дочернего процесса

% Цикл дочернего процесса для получения сообщений

child_loop(I) :-

findall(ChildID, child_pid(ChildID), ChildIDs),

length(ChildIDs, N),

repeat,

thread_get_message(Msg),

( Msg = stop

-> format('Child ~d stopping.~n', [N+1-I]),

retract(child_pid(ThreadID)), % Удаляем идентификатор процесса

!

; Msg = die

-> format('Child ~d dying due to die message.~n', [N+1-I]),

throw(error(child_died, child(I))) % Вызываем ошибку для перезапуска

; format('Child ~d received message: ~w~n', [N+1-I, Msg]),

fail

).

% Остановка родительского процесса

stop :-

stop_children,

format('Parent process stopped.~n').

% Перезапуск дочернего процесса в случае ошибки

:- thread_signal(all, stop). % Завершение всех потоков при завершении родителя

:- use_module(library(thread)).

:- use_module(library(lists)).

par_filter(F, List, Options, Result) :-

option(sublist_size(N), Options, 1),

option(threads(Threads), Options, unlimited),

option(timeout(T), Options, 10000000),

split_list(List, N, Sublists),

length(Sublists, TotalTasks),

effective_threads(Threads, TotalTasks, UsedThreads),

run_parallel(F, Sublists, UsedThreads, T, FilteredParts),

flatten(FilteredParts, Result).

% Разбивает список на подсписки указанного размера

split_list([], _, []).

split_list(List, N, [Sublist | Rest]) :-

length(Sublist, N),

append(Sublist, Remaining, List),

split_list(Remaining, N, Rest).

split_list(List, _, [List]) :- List \= [].

% Определяем, сколько потоков использовать

effective_threads(unlimited, Tasks, Tasks) :- !.

effective_threads(Threads, Tasks, UsedThreads) :- UsedThreads is min(Threads, Tasks).

% Запускаем параллельную обработку с использованием очереди сообщений

run_parallel(F, Sublists, Threads, Timeout, FilteredParts) :-

message_queue_create(Queue),

length(Sublists, NumSublists),

effective_threads(Threads, NumSublists, UsedThreads),

launch_threads(F, Queue, Sublists, UsedThreads, ThreadIDs),

collect_results(ThreadIDs, Queue, Timeout, FilteredParts),

message_queue_destroy(Queue).

% Запускаем потоки, но не добавляем thread_self

launch_threads(F, Queue, Sublists, Threads, ThreadIDs) :-

length(Sublists, NumSublists),

effective_threads(Threads, NumSublists, UsedThreads),

launch_threads_helper(F, Queue, Sublists, UsedThreads, ThreadIDs).

launch_threads_helper(_, _, [], _, []).

launch_threads_helper(F, Queue, [Sublist | Rest], Threads, [ThreadID | RestIDs]) :-

thread_create(process_sublist(F, Queue, Sublist), ThreadID, []),

NewThreads is Threads - 1,

launch_threads_helper(F, Queue, Rest, NewThreads, RestIDs).

% Обрабатывает подсписок и отправляет результат в очередь

process_sublist(F, Queue, Sublist) :-

include(F, Sublist, Filtered),

thread_send_message(Queue, result(Filtered)).

% Собирает результаты из потоков

collect_results([], _, _, []).

collect_results([ThreadID | Rest], Queue, Timeout, [Result | RestResults]) :-

( thread_get_message(Queue, result(Result), [timeout(Timeout)]) -> true ; Result = [] ),

thread_join(ThreadID, _),

collect_results(Rest, Queue, Timeout, RestResults).

% Пример предиката для фильтрации

filter(X) :- X > 5.

% par_filter(filter, [1,2,3,4,5,6,7,8], [sublist_size(2), threads(3), timeout(100)], Result).

% par_filter(filter, [1,2,3,4,5,6,7,8], [], Result).

Соседние файлы в предмете Функциональное и логическое программирование