Задача и одновременный доступ в Юлии - PullRequest
0 голосов
/ 18 сентября 2018

Задача и одновременный доступ в Юлии

Я бы хотел реализовать в Julia управление виртуальными клавиатурами, каждая из которых связана с определенной задачей (или процессом, потоком ...).

В Аде это осуществляется с помощью объектов защищенного типа для этих виртуальных клавиатур и задачи, которая сканирует клавиатуру компьютера, как показано в следующем примере кода.

Как это можно реализовать в Юлии? Документация, по-видимому, плохая при одновременном контроле доступа в Юлии.

with Unchecked_Deallocation;
package Buffer is
 N : constant := 128;
 type Index is mod N;
 type Char_Array is array (Index) of Character;
 protected type Keyboard is
   entry Put (X : in Character);
   entry Get (X : out Character);
 private
   A               : Char_Array;
   In_Ptr, Out_Ptr : Index                := 0;
   Count           : Integer range 0 .. N := 0;
 end Keyboard;
 type Keyboard_Ptr is access all Keyboard;
 procedure Free is new Unchecked_Deallocation (Keyboard, Keyboard_Ptr);
end Buffer;

package body Buffer is
  protected body Keyboard is
    entry Put (X : in Character) when Count < N is
     begin
      A (In_Ptr) := X;
      In_Ptr     := In_Ptr + 1;
      Count      := Count + 1;
    end Put;
    entry Get (X : out Character) when Count > 0 is
     begin
      X       := A (Out_Ptr);
      Out_Ptr := Out_Ptr + 1;
      Count   := Count - 1;
    end Get;
 end Keyboard;
end Buffer;

task Keyboard_Handler;

task body Keyboard_Handler is
   K0        : Character;
   Available : Boolean   := False;
 --  Keyboard_Current : Keyboard_Ptr is defined at upper level
begin
 loop
    Get_Immediate (K0, Available);
    if Available and then Character'Pos (K0) /= 0 then
       Keyboard_Current.Put (K0);
    end if;        
    delay 0.06;
 end loop;
end Keyboard_Handler;

Один из первых шагов - показать, как перехватывать определенные нажатия клавиш (например, стрелки, w, v) и как передавать им канал. Следующее прекрасно работает в Windows, чтобы снабдить основной процесс информацией с клавиатуры:

ch1 = Channel{String}(128)
function run(ch1::Channel)
while true 
  c1 =  ccall((:_getch, "msvcrt.dll "), Int32,())
  if c1 == 224
    c2 =  ccall((:_getch, "msvcrt.dll "), Int32,())
    if c2 == 72 
      put!(ch1, "KEY UP")
    elseif   c2 == 80 
      put!(ch1, "KEY DOWN")
    elseif   c2 == 77 
      put!(ch1, "KEY RIGHT")
    elseif   c2 == 75 
      put!(ch1, "KEY LEFT")
    elseif   c2 == 81 
      put!(ch1, "ALT KEY DOWN")
    elseif   c2 == 73 
      put!(ch1, "ALT KEY UP")
    end
 elseif c1 == Int32('w')
   put!(ch1, "w")
 elseif c1 == Int32('v')  
   put!(ch1, "v")
 end
end
end
buffer = Channel(run)
for x in buffer
   println(x)
end

Теперь я хотел бы передать задачу по своему выбору с клавиатуры. Может быть с чем-то вроде:

using Distributed
addprocs(3)

function tache1(ch::Channel)
 for x in ch
   println("TACHE 1 :",x)
 end
end

function tache2(ch::Channel)
 for x in ch
   println("TACHE 2 :",x)
 end
end

buffer1 = Channel(tache1)
buffer2 = Channel(tache2)

ch1 = buffer1

function run()
 while true 
  c1 =  ccall((:_getch, "msvcrt.dll "), Int32,())
  if c1 == 224
   c2 =  ccall((:_getch, "msvcrt.dll "), Int32,())
   if c2 == 72 
     put!(ch1, "KEY UP")
   elseif   c2 == 80 
     put!(ch1, "KEY DOWN")
   elseif   c2 == 77 
     put!(ch1, "KEY RIGHT")
   elseif   c2 == 75 
     put!(ch1, "KEY LEFT")
   elseif   c2 == 81 
     put!(ch1, "ALT KEY DOWN")
   elseif   c2 == 73 
     put!(ch1, "ALT KEY UP")
   end
   elseif c1 == Int32('w')
    ch1 = Channel(tache1)
   elseif c1 == Int32('v')
    ch1 = Channel(tache2)    
   end
  end
end

f = @spawnat 1 run()

function t1()
  for x in buffer1
    println("11111 ",x)
  end
end

function t2()
  for x in buffer2
    println("22222 ",x)
  end
end

h1 = @spawnat 2 t1()
h2 = @spawnat 3 t2()

for x in buffer1
  println(x)
end

Но это не работает! Может быть, Юля не может сделать то, что Ада может сделать довольно легко ... ?? Или, скорее всего, я очень плохо понимаю многозадачные аспекты Юлии.

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

На самом деле для решения моего вопроса канал не нужен.Простой факт, что Задачи в Julia - просто сопрограммы, гарантирует, что не будет никакого конфликта при доступе с клавиатуры.На платформе Windows демонстрация решения для двух задач, выбранных и управляемых посредством взаимодействия с клавиатурой:

function run1()
  while true 
    c1 =  ccall((:_getch, "msvcrt.dll "), Int32,())
    if c1 == 224
       c2 =  ccall((:_getch, "msvcrt.dll "), Int32,())
       if c2 == 72 
          println("KEY UP1")
       elseif   c2 == 80 
          println("KEY DOWN1")
       elseif   c2 == 77 
          println("KEY RIGHT1")
       elseif   c2 == 75 
         println("KEY LEFT1")
       elseif   c2 == 81 
         println("ALT KEY DOWN1")
       elseif   c2 == 73 
         println("ALT KEY UP1")
      end
    elseif c1 == Int32('w')
      yieldto(tb)
    end
   end
end

function run2()
   while true 
     c1 =  ccall((:_getch, "msvcrt.dll "), Int32,())
     if c1 == 224
        c2 =  ccall((:_getch, "msvcrt.dll "), Int32,())
        if c2 == 72 
          println("KEY UP2")
        elseif   c2 == 80 
          println("KEY DOWN2")
        elseif   c2 == 77 
          println("KEY RIGHT2")
        elseif   c2 == 75 
          println("KEY LEFT2")
        elseif   c2 == 81 
          println("ALT KEY DOWN2")
        elseif   c2 == 73 
          println("ALT KEY UP2")
        end
    elseif c1 == Int32('w')
      yieldto(ta)
    end
  end
end

ta = Task(run1)

tb = Task(run2)

yieldto(tb)
0 голосов
/ 18 сентября 2018

Вы добавили код в вопрос, поэтому я добавил код здесь.Оригинальный пример ниже.

# This works and perhaps is what you wanted to do? 
# I am unsure of some of the tasks you set up in the question's code.


CHAN1 = Channel{String}(0)
CHAN2 = Channel{String}(0)

function tache1()
    while true
        x = take!(CHAN1)
        println("TACHE 1 :", x)
    end
end

function tache2()
    while true
        x = take!(CHAN2)
        println("TACHE 2 :", x)
    end
end

function run()
    try
    println("Esc to exit.")
    chan = CHAN1
    while true 
        c1 =  ccall((:_getch, "msvcrt.dll "), Int32,())
        if c1 == 224
            c2 =  ccall((:_getch, "msvcrt.dll "), Int32,())
            if c2 == 72 
                put!(chan, "KEY UP")
            elseif   c2 == 80 
                put!(chan, "KEY DOWN")
            elseif   c2 == 77 
                put!(chan, "KEY RIGHT")
            elseif   c2 == 75 
                put!(chan, "KEY LEFT")
            elseif   c2 == 81 
                put!(chan, "ALT KEY DOWN")
            elseif   c2 == 73 
                put!(chan, "ALT KEY UP")
            end
        elseif c1 == Int32('w')
            chan = CHAN1
        elseif c1 == Int32('v')
            chan = CHAN2
        elseif(c1 == 27)
            close(CHAN1)
            close(CHAN2)
            exit(0)
        else
            println(Char(c1))
        end
    end
    catch y
        println("Exception caught: ", y)
        exit(1)
    end
end

@async run()
@async tache1()
@async tache2()

while true 
    sleep(0.05) 
end

CUT ---------------------------------------------------------------------

Вот пример (Юлия 1.0)использования библиотеки Gtk для перехвата нажатий клавиш в 3 разных окнах.Вы также можете использовать функции Channel с вызовами Windows C для _getch.

#(note: revised to show Channel usage)

using Gtk.ShortNames

function keypresswindow(chan)

    # This code creates  the Gtk widgets on the screen.
    txt = "Type Y or N"
    win = Window("Keypress Test", 250, 30) |> (Frame() |> 
          ((vbox = Box(:v)) |> (lab  = Label(txt))))

    # this is the keystroke processing code, a function and a callback for the function.
    function keycall(w, event)
        ch = Char(event.keyval)
        put!(chan, ch)
        set_gtk_property!(lab,:label, ch in('n','N','y','Y') ? "You hit the $ch key." : txt)
    end
    Gtk.signal_connect(keycall, win, "key-press-event")

    # this code sets up a proper exit when the widow is closed.
    c = Condition()
    endit(w) = notify(c)
    Gtk.signal_connect(endit, win, :destroy)
    Gtk.showall(win)
    wait(c) 
end

function reader(chan)
    while true
        try 
            c = take!(chan)
            print(c)
        catch
            return
        end
    end
end

function inputwindows(chan, numwindows)
    @async reader(chan)
    println("starting input windows")
    @sync(
    for i in 1:numwindows
        @async keypresswindow(chan)
    end
    )
    println("finished")
end

const chan = Channel(1020)
inputwindows(chan, 3)
...