发表回复 
进度·总结 多持续互斥热键过程的示例
2016-11-25, 15 : 02 (这个帖子最后修改于: 2016-12-28 10 : 42 by robertL.)
Smile 多持续互斥热键过程的示例
功能:使用热键触发的,各热键过程可持续循环,过程彼此间互斥的线程。
    源自我于“求助修改LOOP循环”中的回复,2#
示例×4:形如方式3,有代表性,实现推荐方式4。
    热键a/b/c触发不同的过程,a/b持续、c非持续,过程间互斥。
  1. 代码: (全选)
    ;《多持续互斥热键过程的示例》ahk8.com/thread-6116.html
    ;By RobertL
    #MaxThreadsPerHotkey 2
    a::
        if(!running_a){
            running_a:=true
            while(A_ThisHotkey=="a"){
                Tooltip a
            }
            running_a:=false
        }
        return
    b::
        if(!running_b){
            running_b:=true
            while(A_ThisHotkey=="b"){
                Tooltip b
            }
            running_b:=false
        }
        return
  2. 代码: (全选)
    ;《多持续互斥热键过程的示例》ahk8.com/thread-6116.html
    ;By RobertL
    #MaxThreadsPerHotkey 2
    a::
    b::
    c::    ;stop
        if(running){
            return
        }
        running:=true
        while(A_ThisHotkey!="c"){
            while(A_ThisHotkey=="a"){
                Tooltip a
            }
            while(A_ThisHotkey=="b"){
                Tooltip b
            }
        }
        running:=false
        return
  3. 封装了控制点,直接插入原用户代码即可,其他说明,见3#
    代码: (全选)
    ;《多持续互斥热键过程的示例》ahk8.com/thread-6116.html
    ;By RobertL
    ;====功能部分,无需用户配置====
    ;声明全局变量
    global 目标标签:=""
    ;====功能入口====
    启动(){
        if(目标标签!=A_ThisLabel){
            目标标签:=A_ThisLabel
            SetTimer,%目标标签%,-1
            Exit
        }
    }
    检测退出条件(){
        return 目标标签!=A_ThisLabel
    }
    检测并退出(){
        if(检测退出条件())
            Exit
    }
    ;====用户使用示例====
    a::
        启动()
        while(1){
            Tooltip a
            检测并退出()    ;退出方式1,结束过程(无法进行收尾过程)
        }
        ;return    ;无需
    b::
        启动()
        while(not 检测退出条件()){    ;退出方式2
            Tooltip b
        }
        ;可进行收尾过程
        return
    c::    ;无循环,进而无需检测退出
        启动()
        Tooltip c
        return
  4. 推荐@feiyue 的版本,较以上版本3考虑更周全。代码见4#,详述见7#8#
    新方式:带参数重启脚本实现终止当前过程,开始新过程,见15#
关键
  1. 在循环过程的循环条件/结束循环处进行过程控制
    使用热键A_ThisHotkey,或标签A_ThisLabel
  2. 在循环过程的循环体中结束当前过程
    使用Exit
  3. 热键线程的机制——新的挂起旧的。
    方式1、2中使用#MaxThreadsPerHotkey 2,最初的线程为工作线程,其后的线程被跳过(但状态会更新)。线程A无法结束线程B,需线程自行退出。
  4. 方式3使用定时器开始新热键过程的线程,避免热键线程的竞争、挂起
相关

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢robertL
2016-11-27, 01 : 46 (这个帖子最后修改于: 2016-11-27 01 : 59 by feiyue.)
RE: 多持续互斥热键过程的示例

我的方案,不用大改原来的热键子程序,只要有延时的地方采用新的延时函数即可:


代码: (全选)
/*********************************

  多热键启动互斥线程  By FeiYue

**********************************
*/


;-- 热键子程序全部由AHK主线程的定时器来启动

最后启动标签=

退出所有线程=

Loop {
  if IsLabel(最后启动标签)
  {
    退出所有线程:=0
    SetTimer, %最后启动标签%, -10
  }
  Sleep, 10
}
Return


运行标签(标签="") {
  global
  if IsLabel(标签)
  {
    最后启动标签:=标签, 退出所有线程:=1
    Exit
  }
}

Sleep(t=0) {
  global
  t:=A_TickCount+Round(t)
  Loop {
    if (退出所有线程=1)
      Exit
    if (A_TickCount>=t)
      Break
    Sleep, 10
  }
}

;-- 注意下面的子程序中每行后面都要加上“Sleep(毫秒)”

;-- 下面的例子中,按1热键会循环按1,按2会循环按2,按3停止

$1::运行标签("11")

$2::运行标签("22")

$3::运行标签("停止")


11:
  while (1) {
    send 1
    Sleep( 100 )
  }
  return

22:
  while (1) {
    send 2
    Sleep( 100 )
  }
  return

停止:
  return
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢feiyue
2016-11-27, 12 : 35 (这个帖子最后修改于: 2016-11-27 13 : 29 by robertL.)
RE: 多持续互斥热键过程的示例
@feiyue 借鉴你的思路,我增加了方式3(见1#)。
更简单了:
  • 不用把热键与其过程分离开——不用单独建立标签,浑然一体;
  • 无需添加自动执行段代码;
  • 不集成Sleep功能;
  • 用可退出条件,控制退出流程,亦可直接检测并退出
  • 另,你的“停止”标签或其他使用此方法开始的过程,哪怕是一次性过程,都会持续循环——因为自动执行段中的代码会持续循环。

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-11-27, 22 : 44 (这个帖子最后修改于: 2016-11-29 11 : 54 by feiyue.)
RE: 多持续互斥热键过程的示例

我觉得你的方式3真不错,避免了自动执行段的循环和单独建立标签,所以我把解决方案也改进了一下:


代码: (全选)
/*************************************

  多热键启动互斥线程 v1.0  By FeiYue

**************************************
*/


;-- 下面的子程序中每行后面都尽量加上 Sleep(毫秒),以便随时终止线程

;-- 下面的例子中,按1热键会循环按1,按2会循环按2,按3停止

$1::
  Go()
  while (1) {
    send 1
    Sleep( 100 )
  }
  return

$2::
  Go()
  while (1) {
    send 2
    Sleep( 100 )
  }
  return

$3::
  Go()
  return


;======== 用到的函数及子程序 ========


Go() {
  global
  if (线程优先级!=-1)  ;-- 说明不是定时器启动的
  {
    退出所有线程:=1, 最后启动标签:=A_ThisLabel
    SetTimer, 定时器启动标签, -1, -1
    Exit
  }
  else
  {
    Thread, Priority, 0
    线程优先级:=0
    Critical, Off
  }
}

定时器启动标签:
  if IsLabel(最后启动标签)
  {
    Critical
    退出所有线程:=0, 线程优先级:=-1
    Goto, %最后启动标签%
  }
  Return

Sleep(t=0) {
  global
  t:=A_TickCount+t
  Loop {
    if (退出所有线程=1)
      Exit
    if (A_TickCount>=t)
      Break
    Sleep, 10
  }
}

;
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 2用户表示感谢feiyue
2016-11-28, 13 : 39 (这个帖子最后修改于: 2016-11-28 16 : 20 by robertL.)
RE: 多持续互斥热键过程的示例
代码: (全选)
Class F
  {

       __New() {      
        SetBatchLines, -1
        this.TimePeriod := 1
       }

            presendkeys(strings, duration, Interval, keystate, stopkey*)       {

            Static Ct:=0            
            Mt:= Ct+=1 , R:=Round(Ceil(duration/Interval)) , VK:=LTrim(A_ThisHotkey,"*~$")
            ThRead, Priority, % stopkey[1] = "Hotkeys" ? 0 : 10
            SetKeyDelay, -1, % duration
            For I, AK In stopkey
                   If(AK = VK)
            KeySwitch(VK,(keystate="D" ? "" : "D"), T:="")           
            Loop, Parse, strings
            {   Var:=A_LoopField
               SetFormat, IntegerFast, hex
            SK:=((KV:="vk" . K:=LTrim((V:=GetKeyVK(Var)),"0x")) . CS:="sc" . S:=LTrim((C := GetKeySC(Var)),"0x"))
            SetFormat, IntegerFast, d
            Send, {%SK%}          
            loop, %R%
            {   this.Await( Interval )
            If(Mt != Ct)
            return False
            For I, CK In stopkey
            If ((Kp:=(this.Tracestroke( CK ))) && keystate= "D")
            {  return False
            }  Else if (Kp)
                beak
            If(Keystate!="D")
            If(!Kp,Kp:=False)
            {    return False
            }    }    }
            return TRUE
     }

                stopwatch( R := 0 ) {
        Static P := 0,  F := 0,  Q := DllCall( "QueryPerformanceFrequency", "Int64P",F )
        return Ceil( ( ! DllCall( "QueryPerformanceCounter","Int64P",Q ) + ( R ? (P:=Q)/F : (Q-P)/F ) ) *1000 )
        }

                 Await( MS ) {
                this.stopwatch(True)      
                While (MS < this.stopwatch(False)
                this.Delay(1)                      
                }

                Tracestroke( K )
                {
                Return (this.KeySwitch(K) or GetKeyState(K, "P")) ? True : False
                }

                KeySwitch( K, V:="" , T:="T0.00" )  {                    
                KeyWait, %K% , %V% , %T%            
                Return ( Errorlevel )
                }

                Delay( MS )
        {   If (MS >0) {
            QT:=MS*10000
            return DllCall("ntdll.dll\ZwDelayExecution", "UInt", 0, "Int64*", -QT)
        }                
                }

                ~a::
               while F.pressendkey("123asd456xyz789", 20,2, "D" ,"c","a","d")
               tooltip, %  A_TimeSinceThisHotKey
               return

其实这个用处并不大只是单纯想转码通过一些屏蔽。。想着挺简单的功能居然也花了不少精力, 简直醉。。。。 不过应该可以实现他想要的那些功能。
可能有点小问题 不过没劲头搞了
第一个参数是模拟输出字符串 连着写, 第二个是填写按键时长 第三个是中断按键的判断间隔同时也代表连续发送之间的间隔, 四如果填"D"就是按下退出功能 填别的比如"U"代表抬起退出, 最后是任意可选参数 可以设置预设置多个退出按钮
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-11-28, 21 : 14 (这个帖子最后修改于: 2016-11-28 21 : 17 by robertL.)
RE: 多持续互斥热键过程的示例
@gxsword 帮你改格式了..但排版还是略惊奇,不知道原样是否如此..
看得不是太懂..你用了满多东西,厉害呢..
但好像不太满足本功能哟~

@feiyue 我看了你4#(及你于4#回复我的你修改前的版本),但没太明白,
为什么要通过定时器启动标签去启动最后启动标签..直接通过定时器启动呢?
貌似也无需退出所有线程定时器线程..直接判断当前标签与记录的目的标签——最后启动标签呢?
可能我漏掉了某些组合情况?

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-11-28, 23 : 46 (这个帖子最后修改于: 2016-11-29 09 : 54 by robertL.)
RE: 多持续互斥热键过程的示例
1、模拟情况1:当前正在执行Send x后的Sleep 1000,脚本正在延时,这时先后按下热键a、b、c,
按照:目标标签:=A_ThisLabel,SetTimer,%目标标签%,-1,目标标签已经改为c,定时器启动
了3个,由于Sleep 1000还没完,三个定时器陆续启动并中断当前线程,造成了线程重叠。

要等原来的线程Sleep 1000执行完毕后,再执行新热键要启动的线程的解决方式是:
定时器启动时的优先级定为-1(于是不能中断原来优先级为0的线程),
定时器线程启动后(优先级为0的线程都退出了)再恢复本线程优先级为0。

代码: (全选)
启动(){
    if(目标标签!=A_ThisLabel){
        目标标签:=A_ThisLabel
        SetTimer,%目标标签%,-1,-1
        Exit
    }
    Thread, Priority, 0
}

2、就算经过上述改造,当Sleep 1000执行完毕,并且Sleep 1000之后使用“检测并退出()”
来立即退出线程,然后所有重叠的优先级为0的线程都用“检测并退出()”退出了,
此时优先级为-1的三个定时器都陆续陆续立即启动,相互中断,又造成了线程重叠,如果
通过一个“定时器启动标签+最后启动标签”来中转启动,则三个定时器只执行最后一个。

3、尽量不要使用A_ThisLabel作为“检测退出条件”,因为这样使脚本中不能使用Goto
或Gosub;随着热键的启动,“目标标签”全局变量也变化多端,再与A_ThisLabel来比较
有较多不确定性,不如直接来一个“退出所有线程:=1”,强制所有优先级为0的线程都退出。

4、模拟情况2:当前正在执行热键a(定时器线程),此时又按了热键a,此时新线程会直接
中断旧线程产生叠加。这种情况如果没有一个“定时器线程”变量作为区分标记,是无解的。

以上就是我对于极端情况下确保热键互斥的思考,普通情况下,@robertL 你的方式3也够了。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢feiyue
2016-11-29, 09 : 49 (这个帖子最后修改于: 2016-11-29 10 : 28 by robertL.)
RE: 多持续互斥热键过程的示例
@feiyue 详述的4点都很在理,学习了!
已在1#更新链接。
  • 通过优先级——新线程先低,等旧线程退出后再恢复,以使新线程等待旧线程从出口退出,而不中途中断旧线程,不产生叠加
  • 过程一律由定时器发起,避免叠加

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-11-29, 12 : 10 (这个帖子最后修改于: 2016-11-29 12 : 59 by gxsword.)
RE: 多持续互斥热键过程的示例
(2016-11-28 21 : 14)robertL 提到:  @gxsword 帮你改格式了..但排版还是略惊奇,不知道原样是否如此..
看得不是太懂..你用了满多东西,厉害呢..
但好像不太满足本功能哟~

@feiyue 我看了你4#(及你于4#回复我的你修改前的版本),但没太明白,
为什么要通过定时器启动标签去启动最后启动标签..直接通过定时器启动呢?
貌似也无需退出所有线程定时器线程..直接判断当前标签与记录的目的标签——最后启动标签呢?
可能我漏掉了某些组合情况?

必须是Sublime的锅…… 其实作为互斥要求来说,里面很多东西是多余的, 比如强制转换十六进制sc码什么的, 我当初的目的是不想定义过多的热键,实际使用又有各种问题打了n个补丁, 不满足功能是哪方面? 如果是包含发送自生的停止键是要等待抬起运行的, 可能会出现迟滞?

其实这个帖子要解决的问题我是挺好奇, 因为热键互相中断困扰一直我没有很好的解决
应用你的方案三 出现了 一种情况就是 我连续按一个热键时,重复启停的定时器 造成了键被卡住, 还好没死, 也可能是我另一个包含全局模拟按键API函数的锅,但是定时器和热键的冲突是很明显存在的 和 feiyue讲得差不多,A_ThisLabel 在变化太不稳定了, 它时有热键函数过于复杂多次改变标签 造成过快退出 不知是否因为类的原因? 我又试了已A_ThisFunc 更加不可靠了, 似乎ThisHotKey更符合实际情况
定时器管理还有一个问题就是延迟 就算是设为 -1 Exit 当前的线程再启动 如果上次线程还有一个比较长得处理的话, 会等待一个比较恶心延迟的然后又此时你又再次按下热键的话……
难道是我理解问题? 你们讨论的是等待旧线程完成的方案, 我是考虑的马上执行新线程, 终止旧过程?
我其实是想考虑使插入一个异步过程来实现,这样不会在循环里进行太多次判断,这样消费会大大减小,因为使用了精确度小于0.1毫秒的休眠功能,和飞秒级的时间对照,资源占​用上涨太多, AHK似乎不能异步? 定时器也不算啊
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢gxsword
2016-11-29, 13 : 01 (这个帖子最后修改于: 2016-11-29 13 : 23 by feiyue.)
RE: 多持续互斥热键过程的示例
@gxsword 想要立即终止旧线程,要尽量使用我那个Sleep(毫秒)函数(因为它内部包含了退出检测),
每个操作指令后面都加这个函数,即使延时为0,并替换掉Sleep、KeyWait、WinWait等指令的等待。
如果追求即时反应,马上执行新线程,必然中断旧线程,因为旧线程不会被新线程终止,只能自己退出。
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 2用户表示感谢feiyue
2016-11-29, 13 : 35 (这个帖子最后修改于: 2016-11-29 13 : 44 by robertL.)
RE: 多持续互斥热键过程的示例
gxsword 提到:不满足功能是哪方面?
我原指,应用于可自定义的热键过程,而非仅仅是模拟发送这单一功能,但你都使用异步概念了,何况把此嵌入的功能使用参数在调用时配置,亦能任意自定义,只是不太像传统的热​键过程了。

gxsword 提到:应用你的方案三 出现了 一种情况就是 我连续按一个热键时,重复启停的定时器 造成了键被卡住
这是我方案3的不足——重复热键会进入热键过程,而是应该如8#所述“过程一律由定时器发起,避免叠加”。
但应该不是重复定时器的问题,而且仍应该能退出,他们都在于条件目标标签!=A_ThisLabel而已。
@feiyue 的方案已解决此问题。

gxsword 提到:定时器和热键的冲突是很明显存在的 和 feiyue讲得差不多,A_ThisLabel 在变化太不稳定了
其实我还不太理解,A_ThisLabel 有什么问题。
我仅想到
feiyue 提到:因为这样使脚本中不能使用Goto或Gosub,并在其中进行条件判断
因为在启动检测退出条件中使用它做判断,如果在热键的主标签下使用他们俩,而非Goto或Gosub中我感觉不会有副作用。

gxsword 提到:你们讨论的是等待旧线程完成的方案, 我是考虑的马上执行新线程, 终止旧过程?
1# 提到:热键线程的机制——新的挂起旧的。
方式1、2中使用#MaxThreadsPerHotkey 2,最初的线程为工作线程,其后的线程被跳过(但状态会更新)。线程A无法结束线程B,需线程自行退出。
提及:线程A无法结束线程B,需线程自行退出
则需要在线程中使用较小的间隔去检测更外层的控制条件,以便提前结束等待。
你的异步过程在循环里判断应该也是这个道理。
这是模拟出来的异步,效率当然比不过系统级的。
我觉得 @feiyue 的方案效率可以接受。

gxsword 提到:如果上次线程还有一个比较长得处理的话
所以要求此上次线程有个合理的出口。比如我的检测退出条件、@feiyueSleep

我在想能否使用AHK里的伪线程的优先级去模拟覆盖/隐藏旧的本该停止的线程,使其如同被结束了样,再不被执行?费点内存而已吧?@feiyue

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢robertL
2016-11-29, 14 : 22 (这个帖子最后修改于: 2016-12-02 08 : 11 by robertL.)
RE: 多持续互斥热键过程的示例
(2016-11-29 13 : 01)feiyue 提到:  @gxsword 想要立即终止旧线程,要尽量使用我那个Sleep(毫秒)函数(因为它内部包含了退出检测),
每个操作指令后面都加这个函数,即使延时为0,并替换掉Sleep、KeyWait、WinWait等指令的等待。
如果追求即时反应,马上执行新线程,必然中断旧线程,因为旧线程不会被新线程终止,只能自己退出。

如果按我自己的那个休眠函数比如
代码: (全选)
F.Await( 毫秒 ){
    this.stopwatch(True)  
    While (MS < this.stopwatch(False)
    If (退出所有线程=1)
            Exit
    Else  this.Delay(1)                      
}
这样每秒会检测上千次会不会有影响?
要么直接插入每个休眠函数中?那不是一样 混乱了……
而且类中 不能 Goto 到新启动标签吧?

(2016-11-29 13 : 35)robertL 提到:  
gxsword 提到:不满足功能是哪方面?
我原指,应用于可自定义的热键过程,而非仅仅是模拟发送这单一功能,但你都使用异步概念了,何况把此嵌入的功能使用参数在调用时配置,亦能任意自定义,只是不太像传统的热​键过程了。

gxsword 提到:应用你的方案三 出现了 一种情况就是 我连续按一个热键时,重复启停的定时器 造成了键被卡住
这是我方案3的不足——重复热键会进入热键过程,而是应该如8#所述“过程一律由定时器发起,避免叠加”。
但应该不是重复定时器的问题,而且仍应该能退出,他们都在于条件目标标签!=A_ThisLabel而已。
@feiyue 的方案已解决此问题。

确实不是定时器的问题 而是 函数模拟的全局几个不同的健击被认为是自己的热键重复于是产生了多次互相中断,还让有些键没产生抬起……于是卡死, 我尝试加入了临时关闭当前热键的指令, 过程完成再重启, 但感觉又与实时终止相饽,总不可能临时禁用全部热键吧?而且有点奇怪 按键历史中显示 发送的键击 是 A 字头 那不是代表可以分辨非人工键击么? 为何依然会激发热键?

gxsword 提到:定时器和热键的冲突是很明显存在的 和 feiyue讲得差不多,A_ThisLabel 在变化太不稳定了
其实我还不太理解,A_ThisLabel 有什么问题。
我仅想到
feiyue 提到:因为这样使脚本中不能使用Goto或Gosub,并在其中进行条件判断
因为在启动检测退出条件中使用它做判断,如果在热键的主标签下使用他们俩,而非Goto或Gosub中我感觉不会有副作用。

函数热键的Label 会是变成这个函数的名称 热键是一个线程, 定时器启动的是一个新线程, 那么被Exit的是这个定时器的线程吧?
当新热键击发生时,首先判断这次线程标签是否重复的 那么如果是快速双击不会终止上一次未运行完的线程依然将其挂起, 如果线程非重复
那么Exit变成了岂不是将新线程一起结束了?
还是定时器应该放在Exit之前? 如果快速对不同的热键击健,会对定时器的工作有次序发生影响吧? 在我对热键设置了不同的优先级情况下

gxsword 提到:你们讨论的是等待旧线程完成的方案, 我是考虑的马上执行新线程, 终止旧过程?
1# 提到:热键线程的机制——新的挂起旧的。
方式1、2中使用#MaxThreadsPerHotkey 2,最初的线程为工作线程,其后的线程被跳过(但状态会更新)。线程A无法结束线程B,需线程自行退出。
提及:线程A无法结束线程B,需线程自行退出
则需要在线程中使用较小的间隔去检测更外层的控制条件,以便提前结束等待。
你的异步过程在循环里判断应该也是这个道理。
这是模拟出来的异步,效率当然比不过系统级的。
我觉得 @feiyue 的方案效率可以接受。

gxsword 提到:如果上次线程还有一个比较长得处理的话
所以要求此上次线程有个合理的出口。比如我的检测退出条件、@feiyueSleep

我在想能否使用AHK里的伪线程的优先级去模拟覆盖/隐藏旧的本该停止的线程,使其如同被结束了样,再不被执行?费点内存而已吧?@feiyue
我设想是设置一个线程池,首先在线程池里对所有线程进行初步筛选 新线程级别高就运行 同时对旧线程实施终止,级别相同 挂起旧线程 运行新线程 级别较低 依然运行旧线程 略微延迟新线程 新线程级别如果最低 便忽视新线程 不执行 依然运行旧线程。
伪多线程这样是不是想多了?
按道理说如果对每个线程都进行编号的话 应该是可以在A线程中终止B他线程的 用winAPI 中的 那个取得线程名的函数?
要使用回调才能是异步 好像是有可能实现 OnMessage()
不就是一个异步过程么?
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-11-30, 20 : 05 (这个帖子最后修改于: 2016-12-02 21 : 37 by gxsword.)
RE: 多持续互斥热键过程的示例
代码: (全选)
设置(开关){
        global 运行, 线程
        If( 线程 > 0 ) {        
        线程 := A_ThisLabel
        } else 线程 := ""
        return ( 开关 ) ? (运行:=1) : (运行:=0)
        }  
                
    检测中断() {
        If( 线程<>A_ThisLabel )
           {
            线程:=A_ThisLabel
             Exit
           }  
    }

    Await(休眠间隔, 检测退出:=true){   ;可更据需要是否使用终止功能
        timeout := DllCall("winmm.dll\timeGetTime", "UInt")+休眠间隔    ;使用多媒体计时器提供更高的精度
        while (timeout>DllCall("winmm.dll\timeGetTime", "UInt"))
        {
        If ( 检测退出 )
                检测中断()
        Sleep 10
        }
}
a::
    设置A(true)        ;流程 开头与结尾 各放一个
       If(!检测中断()){
       Sleep 10      
    }  ;   可选多种方式退出
    记录.设置A(false)
    return
b::
    记录.设置B(true)
    Loop
    Await(20, true)
       ;  feiyue的放在休眠函数里也不错
    Tooltip b
    记录.设置B(False)
    return

c::    ;每个热键的函数其实是一样的, 但必须用不同的函数名
    记录.设置C(true)
    Tooltip c
    记录.设置C(false)
    return
怎么手机修改的乱七八糟的……
不过本来就些情况没考虑周全, 比如不能自我终止。
现在最好的方案还是feiyue的 实话[/quote]
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-12-02, 09 : 07 (这个帖子最后修改于: 2016-12-02 09 : 19 by robertL.)
RE: 多持续互斥热键过程的示例
gxsword 提到:如果按我自己的那个休眠函数比如..
这样每秒会检测上千次会不会有影响?
要么直接插入每个休眠函数中?那不是一样 混乱了……
模拟的比不上原生的。
目前没有原生的支持中断的延迟函数/命令。
以上@feiyue 只构造了一个模拟带中断的延迟函数——Sleep
使用较AHK自身代码执行时间小的检测时间,好像无意义。比如Sleep的时间精度是10ms,去构造个0.1毫秒、飞秒级别也不能更优先地影响原控制流。

gxsword 提到:我设想是设置一个线程池
问题在于不支持复杂的线程,也无法能模拟吧?
如果支持了,则如线程池之类的管理也理所当然该支持了。

gxsword 提到:按道理说如果对每个线程都进行编号的话 应该是可以在A线程中终止B他线程的 用winAPI 中的 那个取得线程名的函数?
AHK中的伪线程没提供操作接口。适用于简单的情况。
真复杂了,可以考虑AHK_H,支持真正多线程了。(到时又有新的要考虑的因素了,比如线程竞争、共享)

gxsword 提到:要使用回调才能是异步 好像是有可能实现 OnMessage()
不就是一个异步过程么?
回调和异步好像没有关系。
OnMessage()是中断事件。
有了并行的过程,才能讲异步吧。我概念上也模糊..
反正需要实现线程间彼此独立、并行,而非新的挂起旧的,再考虑更上层的调度。



你代码里的[/align]是论坛代码吗?...只有后半部分呢..
代码: (全选)
_New() {
  this.终止线程:=0
  this.线程标志:=0
}
的初始化好像不用放到_New函数里,作为普通的实例变量即可,此处没有用到需要特殊处理的情况。

线程终止”仅出现于检测中断()中,应该是“终止线程”吧...(已在你代码上修改)

里面的“线程标志”计数也没看懂...
相当于“是否存在已运行的同名线程”?每次false关闭时,结束其他所有线程?

AwaitLoop..until缺括号..
奇怪,怎么复制的代码感觉缺东西...
this.Delay( 1 )后面的注释“;”也缺...
可能是我打开网页时丢数据了..
代码: (全选)
While (检测退出)
    检测中断()
this.Delay( 1 )
这样会卡住,直至条件满足时Exist。 @gxsword

One for all, but man for himself

帮推广:AHK知乎专栏
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
2016-12-18, 01 : 39 (这个帖子最后修改于: 2016-12-18 02 : 02 by feiyue.)
RE: 多持续互斥热键过程的示例

我觉得采用简单重启的方式更省事一些,因为这样不用修改原来的热键代码(不用添加检测退出函数)。
缺点是按热键后反应速度有点慢,而且重启的间隔会丧失热键功能(快速按时可能会发送原来的按键)。


代码: (全选)
/*************************************

  互斥的多热键循环过程 v1.5  By FeiYue

**************************************
*/

; 自动执行段末尾加上以下代码,再在热键后面加上:开始()

#SingleInstance force
if 0>0
{
  s=%1%
  if IsLabel(s)
    Goto, %s%
}
开始(标签="") {
  static 初次运行
  if !初次运行
  {
    初次运行:=1
    Return
  }
  Critical
  标签:=标签="" ? A_ThisLabel : 标签
  Run, %A_AhkPath% /r /f "%A_ScriptFullPath%" %标签%
  Sleep, 1000
  Exit
}
Return


$1::
开始()
Loop, {
  ToolTip, 111-%A_Index%
  Sleep, 100
}
Return


$2::
开始()
Loop, {
  ToolTip, 222-%A_Index%
  Sleep, 100
}
Return

$3::开始()
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
[+] 1用户表示感谢feiyue
2018-06-05, 09 : 41
RE: 多持续互斥热键过程的示例
顶哈 !!!!
查找这个用户的全部帖子
表示感谢 引用并回复 移动视图置页面顶端
发表回复 


论坛跳转:


联系我们 | Autohotkey 中文站 | 回到顶部 | 回到正文区 | 精简(归档)模式 | RSS 聚合