多线程与单线程的区别:

  • 单线程顺序执行:ABCDEFG,HIJKLMN
  • 单线程异步执行:ABC,KLMN,EFGHI,错开执行避免I/O之类的长时间等待卡住线程【WinWait】
  • 多线程:一个进程内可有多个线程ABCDEFG同时执行互不干扰
  • 多进程:创建多个进程ABCDEFG并互相通信,来达到仿多线程的效果。

 

不控制主进程的话,使用方法如下:

新建进程示例,可以是代码,也可以是路径:

进程1 := ComProcess("C:\Program Files\AutoHotkey\Lib\FindText.ahk")

 

在目标进程中调用一个名为 "Function" 的函数:

进程1.Function(params)

 

获取进程1的一个全局变量:

value := 进程1["VarName"]
value := 进程1.VarName

 

对进程1的一个全局变量赋值:

进程1["VarName"] := value
进程1.VarName := value

 

对进程1创建一个Class的实例:

value := 进程1["__ComProcess"].__New("ClassName", params)

 

另一个精简但不能共享对象的多进程:多进程代替多线程函数 – 精简版

 

尝试双向通信的多进程库,ComProcess函数用来控制和调用新进程很方便。但是新进程向主进程发送控制,我写了一个Class 变量赋值回调来实现。

 

完整的双向通信示例:

#Requires AutoHotkey v1.1.33+
#SingleInstance Force
SetBatchLines -1

Gosub 加载新进程标签

进程1.进程共享变量 := New 变量赋值回调("新进程触发回调函数")

Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y400, P主进程 - 互相通信同步演示,请输入文字

Loop {
  Sleep 80
  MouseGetPos, x, y
  ToolTip % "P-主进程持续运算演示-" A_Index, x+10, y-70
}
Return


同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程1.Gui同步更新(获取编辑框内容, "通信显示")
Return

GuiClose:
  ExitApp
Return


; F3键做新进程的开、关、一键开关的演示【只有主进程端能够新建进程】
F3::
  ; 进程1 := ComProcess(新代码1)
  进程1 := ""
  ; 进程1:=(Toggle:=!Toggle) ? ComProcess(新代码1) : ""
Return


新进程触发回调函数(newValue) {
  GuiControl,, 通信显示, %newValue%
}

class 变量赋值回调 {
  __New(changeCallback) {
    this._onChangeCallback := Func(changeCallback)
  }
  回调变量[] {
    get {
      return this._value
    }
    set {
      this._value := value
      , (this._onChangeCallback && this._onChangeCallback.Call(this._value))
      return this._value
    }
  }
}


加载新进程标签:
新代码1=
( ` %
Gui -MinimizeBox -MaximizeBox +AlwaysOnTop
Gui Add, Edit, w300 R2 v通信显示 g同步发送
Gui Show, x850 w330 y500, F3新进程 - 互相通信同步演示,请输入文字

Loop {
  Sleep 80
  MouseGetPos, x, y
  ToolTip % "F3-新进程持续运算演示-" A_Index, x+10, y-30
}
Return

同步发送:
GuiControlGet, 获取编辑框内容,, 通信显示
进程共享变量.回调变量 := 获取编辑框内容
Return

Gui同步更新(Value, ControlID) {
  GuiControl,, %ControlID%, %Value%
}

GuiClose:
  ExitApp
Return
)

进程1 := ComProcess(新代码1)
Return

/*
在目标进程中调用一个名为 "Function" 的函数。
进程1.Function(params)

获取进程1的一个全局变量
value := 进程1["VarName"]
value := 进程1.VarName

对进程1的一个全局变量赋值
进程1["VarName"] := value
进程1.VarName := value

创建一个Class的实例
value := 进程1["__ComProcess"].__New("ClassName", params)

已知限制:
如果脚本在运行远程脚本调用的方法时退出,则远程脚本将收到错误。
AutoHotkey 如何在本地与 COM 对象交互以及 AutoHotkey 对象如何通过 COM 接口响应请求也存在一些限制。
  变量无法通过 ByRef 传递到远程对象。
  有些调用是不明确的;例如,foo.bar 触发器 foo.__Call  进而foo.__Get。
*/

; By dbgba   Thank thqby
ComProcess(PathsOrCode, v1Interpreter="", Timeout=30, NoTrayIcon="#NoTrayIcon") {
  Static IDispatch, ComProcessNum := 0
  , _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, "int64"), "int64"))
  , PIDLabel := DllCall("GetCurrentProcessId")

  if (v1Interpreter="") {
    if A_Is64bitOS
      SetRegView 64
    RegRead, InstallDir, HKLM\SOFTWARE\AutoHotkey, InstallDir
    v1Interpreter := InstallDir="" ? A_AhkPath : InstallDir "\AutoHotkey.exe"
  }

  if !FileExist(v1Interpreter)
    throw Exception("请将参数2的AHK解释器路径设置正确!")

  lresult := DllCall("oleacc\LresultFromObject", "Ptr", &IDispatch, "Ptr", 0, "Ptr", &(client := { proxy: 0 }), "Ptr")
  if IsObject(PathsOrCode) {
    t := PathsOrCode, PathsOrCode := ""
    For __, p in t
      PathsOrCode .= "`n#include " p
  }

  v1script := Format("
  (
    #Persistent
    " NoTrayIcon "
    class __ComProcess {
      __New(name, args*) {
        static _ := (VarSetCapacity(IDispatch, 16), NumPut(0x46000000000000c0, NumPut(0x20400, IDispatch, ""int64""), ""int64""), DllCall(""oleacc\ObjectFromLresult"", ""ptr"", {}, ""ptr"", &IDispatch, ""ptr"", 0, ""ptr*"", idisp := 0), ComObject(9, idisp).proxy := new __ComProcess(), ObjRelease(idisp)), hMapping := DllCall(""kernel32\CreateFileMapping"", ""Ptr"", -1, ""Ptr"", 0, ""UInt"", 0x4, ""UInt"", 0, ""UInt"", 4, ""Str"", ""AHKLoadStatus" PIDLabel . ++ComProcessNum """), pView := DllCall(""kernel32\MapViewOfFile"", ""Ptr"", hMapping, ""UInt"", 0x2, ""UInt"", 0, ""UInt"", 0, ""UInt"", 4)
        return IsObject(name) ? new name(args*) : new %name%(args*)
      }
      __Call(name, args*) {
        Global
        if (IsObject(args) && %name%!="""")
          return __ComProcessVar__ := %name%
        return %name%(args*)
      }
      ; __Get(name) COM机制无法触发,故删掉
      __Set(name, val) {
        Global
        return %name% := val
      }
      __Delete() {
        SetTimer __ComProcessExitApp__, -1
        return
        __ComProcessExitApp__:
          ExitApp
      }
    }
    {}
  )", lresult, FileExist(PathsOrCode) ? "" : PathsOrCode)

  if (v1Interpreter ~= "i)\.dll$") {
    if (!DllCall("GetModuleHandle", "str", v1Interpreter) && !DllCall("LoadLibrary", "str", v1Interpreter)) {
      DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
      throw Exception("load AutoHotkey.dll fail")
    }
    if !(threadID := DllCall(v1Interpreter "\NewThread", "str", v1script "`n" (FileExist(PathsOrCode) ? "#Include " PathsOrCode : ""), "str", "", "str", "", "cdecl uint")) {
      DllCall("oleacc\ObjectFromLresult", "ptr", lresult, "ptr", &IDispatch, "ptr", 0, "ptr*", idsp := 0), ObjRelease(idisp)
      throw Exception("Failed to load script")
    }
    _exec := {ProcessID : DllCall("GetCurrentProcessId")}
  } else {
    if FileExist(PathsOrCode)
      _exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /include """ PathsOrCode """ *")
    else
      _exec := ComObjCreate("WScript.Shell").Exec("""" v1Interpreter """ /CP0 *")
    _exec.StdIn.Write(v1script), _exec.StdIn.Close()
  }

  Loop % Timeout*1000//15 {
    Sleep 15
    hMap := DllCall("kernel32\OpenFileMapping", "UInt", 0x2, "Int", 0, "Str", "AHKLoadStatus" PIDLabel . ComProcessNum)
    , pView := DllCall("kernel32\MapViewOfFile", "Ptr", hMap, "UInt", 0x2, "UInt", 0, "UInt", 0, "UInt", 4)
  } Until ((isLoaded := NumGet(pView+0, 0, "Int"))=0)
  if (isLoaded!=0)
    Throw Exception("AHK新进程启动超时或故障!")
  Sleep 10
  return client.proxy
}

 

声明:站内资源为整理优化好的代码上传分享与学习研究,如果是开源代码基本都会标明出处,方便大家扩展学习路径。请不要恶意搬运,破坏站长辛苦整理维护的劳动成果。本站为爱好者分享站点,所有内容不作为商业行为。如若本站上传内容侵犯了原著者的合法权益,请联系我们进行删除下架。