Как дождаться ввода от пользователя и продолжить работу с кодом в параллельном программировании erlang? - PullRequest
0 голосов
/ 31 января 2019

Я работаю с параллельным программированием в Erlang, где я пытаюсь обмениваться сообщениями между двумя пользователями.Итак, я жестко запрограммировал один набор сообщений, который отправлялся как сообщение одно за другим от user1 другому user2, я читаю ввод с клавиатуры и передаю этот ввод как ответ пользователю1.Но во время его выполнения ввод не берется, и передача сообщения продолжается без ввода и запрашивает ввод наконец после завершения всех процессов.

-module(third).
-import(lists,[nth/2]).
-export([start/0,user2/5,user1/3,inp/1]).

inp(P) ->
{ok, [S]} = io:fread("entry: \n", "~s"),

P ! S.


user2(0, USERID1,_,_,_) ->
USERID1 ! bye,
io:format("finish");

user2(N, USERID1,Mess,Rep,K) ->
USERID1 ! {message, self(),Mess,K},
receive
    reply ->

    S=self(),
        spawn(third, inp, [S])
end,
user2(N-1, USERID1,Mess,Rep,K+1).

user1(Mess,Rep,K) ->
receive
        bye ->
            io:format("conversation over");
        {message, USERID2,Mess,K} ->
            io:format("~p~n",[nth(K,Mess)]),
            USERID2 ! reply,
            user1(Mess,Rep,K+1)
    end.

start() ->
Mess=["HEY","sup","how are you","yhank you","bye"],
USERID1=spawn(third, user1, [Mess,Rep,1]), 
spawn(third, user2, [5,USERID1,Mess,Rep,1]).

Как мне дождаться ввода и затем передать этосообщение.При запуске модуля запуска вывод выглядит следующим образом -

1> c(third).
{ok,third} 
2> third:start().
"HEY"
<0.77.0>
entry: 
"sup"
entry: 
entry: 
"how are you"
entry: 
entry: 
"yhank you"
entry: 
entry: 
"bye"
entry: 
finishentry: 
entry: 
conversation overentry: 

Когда он запрашивает ввод, он должен дождаться ввода и затем продолжить.

Ответы [ 3 ]

0 голосов
/ 02 февраля 2019

Посмотрите, поможет ли это:

-module(my).
-compile(export_all).

start() ->
    register(user1, spawn(my, user1, [["Hello!", "How are you?", "Bye"]]) ),
    register(user2, spawn(my, user2, []) ),
    start_finished.

user1([]) ->
    {user1, terminated};
user1([String|Strings])->
    timer:sleep(500), %% See discussion below.
    user2 ! String,

    receive
        Reply -> io:format("user1 received: ~s~n", [Reply])
    end,

    user1(Strings).

user2() ->
    receive
        "Bye" -> io:format("Bye~n");
        Msg -> 
            Prompt = io_lib:format("~s~n>>> ", [Msg]),
            Reply = io:get_line(Prompt),
            user1 ! Reply,
            user2()
    end.

В оболочке:

~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}

2> my:start().
start_finished
Hello!
>>> Hi there!
user1 received: Hi there!

How are you?
>>> Good, and you?
user1 received: Good, and you?

Bye
3> 

Я не уверен, зачем мне нужен вызов timer:sleep(), но он предотвращает какой-то типсостояние гонки, которое приводит к неисправности io:get_line().

0 голосов
/ 03 февраля 2019

Версия, приведенная ниже, работает так, как вы ожидаете - по крайней мере, я так думаю, потому что нет ни большого количества комментариев ни в вашем вопросе, ни в вашем коде.

она содержит 2 модификации:

  1. Как сказал Odobenus, если вы вызываете функцию inp, функция user2 немедленно получает возвращаемое значение spawn, которое является pid порожденного процесса, а не строку, введенную пользователем.Таким образом, user2 больше ничего не ждет.Процесс все еще существует, поэтому он предложит "entry:", дождется ввода, но не будет его использовать, и строка будет потеряна при вводе.
  2. В последний раз возникла другая проблемастрока, когда вы вызываете функцию user2.Опять же, функция запуска немедленно останавливается, когда она получает pid нового процесса;поскольку он был запущен командой оболочки, оболочка сразу же получает контроль над io, и процесс user2 никогда не получит строку, введенную пользователем, поскольку она будет интерпретироваться оболочкой как команда.

'' '

-module(third).

-export([start/0,user2/4,user1/2,inp/1]).

inp(P) ->
    S = io:get_line("entry: \n"),
    P ! S.


user2(0, USERID1,_,_) ->
    USERID1 ! bye,
    io:format("finish");

user2(N, USERID1,Mess,K) ->
    USERID1 ! {message, self(),Mess,K},
    io:format("user2 wait for reply~n"),
    receive
        reply ->
            S=self(),
            inp(S)
    end,
    user2(N-1, USERID1,Mess,K+1).

user1(Mess,K) ->
    receive
        bye ->
            io:format("conversation over");
        {message, USERID2,Mess,K} ->
            io:format("~p~n",[lists:nth(K,Mess)]),
            USERID2 ! reply,
            user1(Mess,K+1)
    end.

start() ->
    Mess=["HEY","sup","how are you","yhank you","bye"],
    USERID1=spawn(third, user1, [Mess,1]),
    user2(5,USERID1,Mess,1).

' ''

Однако в вашем примере два пользовательских процесса на самом деле не связываются: они не проверяют сообщения и обмениваются каждый разполная коллекция сообщений.Я предлагаю вам изучить эту другую версию, по умолчанию, после 5 обменов, пользователь 1 закрывает чат, но пользователь 2 может остановить его раньше, введя сообщение "пока".

'' '

-module(third).

-export([start/0,user2/1,user1/1]).


user2(USERID1) ->
    S = io:get_line("entry: \n"),
    USERID1 ! {message, self(),S},
    io:format("user2 wait for reply~n"),
    maybe_continue_user2(USERID1,S).

maybe_continue_user2(_,"bye\n") ->
    io:format("User2 ends the chat~n");
maybe_continue_user2(USERID1,_) ->
    receive
        {reply,"bye"} ->
            io:format("bye, close chat~n");
        {reply,Mess} ->
            io:format("user2 got ~p~n",[Mess]),
            user2(USERID1)
    end.

user1([]) ->
    io:format("User1 ends the chat~n");
user1([H|T]) ->
    receive
        {message,_,"bye\n"} ->
            io:format("user 1: conversation over~n");
        {message, USERID2,Mess} ->
            io:format("~p~n",[Mess]),
            USERID2 ! {reply,H},
            user1(T)
    end.

start() ->
    Mess=["HEY","sup","how are you","thank you","bye"],
    USERID1=spawn(third, user1, [Mess]),
    user2(USERID1).

'' '

пример, когда пользователь 2 останавливает чат:

9> third:start().
entry:
hi
user2 wait for reply
"hi\n"
user2 got "HEY"
entry:
how are you?
user2 wait for reply
"how are you?\n"
user2 got "sup"
entry:
bye
user2 wait for reply
user 1: conversation over
User2 ends the chat
ok
10>
0 голосов
/ 31 января 2019

код, который читает со стандартного ввода.Вы запускаете его в отдельном процессе

spawn(third, inp, [S])

каждый раз, когда процесс user2 получает атом 'reply'

И, кстати, результат ввода пользователя будет отправлен процессу user2 и никогда не будет использоваться.

...