Julia中的任务和并发访问

时间:2018-09-18 07:40:02

标签: concurrency julia ada

Julia中的任务和并发访问

我想在Julia中实现虚拟键盘的管理,这些虚拟键盘与一个专用任务(或进程,线程...)相关联。

在Ada中,这是通过对这些虚拟键盘使用保护类型的对象以及扫描计算机键盘的任务来进行管理的,如以下代码示例中所述。

如何在Julia中实现呢?显然,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

但是它不起作用!可能是茱莉亚(Julia)无法轻松完成艾达(Ada)可以做的事情... ??或者,也许我对Julia的多任务方面了解得很糟。

2 个答案:

答案 0 :(得分:2)

您在问题中添加了一些代码,因此我在此处添加了代码。 原始示例在此下方。

# 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

剪切---------------------------------------------- -----------------------

这里是一个示例(Julia 1.0),该示例使用Gtk库在3个不同的窗口中拦截击键。您也可以将Channel函数与对_getch的Windows C调用一起使用。

#(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)

答案 1 :(得分:0)

实际上,我的问题的解决方案不需要Channel。 Julia中的Tasks只是协程的简单事实,保证不会对键盘访问产生冲突。在Windows平台上,通过键盘交互选择和驱动2个任务的解决方案的演示是:

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)