Thread global variables and thread ID

Propose new features and changes
2_05
Posts: 9
Joined: 09 May 2018, 10:28

Thread global variables and thread ID

16 Sep 2018, 04:51

Many applications can be open multiple times, so there are several PID's active for the same application. If a Thread is started on one process of an application, I want to insure that all functions work on the same processes even when other windows have become active in between. I know a few ways of doing this.
  1. Pass the PID along with each function call.
  2. Set the LastFoundWindow. This required all functions to always restore the 'last found window' if that function temporarily has to act on another window. The last found window is thread specific.
  3. Store the PID in a global variable. This is not stable when a thread can be interrupted by another thread which changes the global variable.
There are certain built-in variables that are thread specific, like A_TitleMatchMode. To me it would be nice to be able to define my own thread specific variables. Variables that are global but only within the same thread. When another thread interrupts, it can define its own value for such variables, but it does not change anything for the thread that was interrupted.

Similar to the definition of super global variables global var1, I would propose thread variables to be defined by thread var1 or threadglobal var1.

Besides the thread variables it is also helpful to have a unique ID for each thread within the script, e.g. A_ThreadID. With A_ThreadID you can for example store values in a global associative array and call global PIDs[A_ThreadID] to retrieve thread specific values. I'm not sure if Autohotkey uses thread_id's internally, I think in that case it's a small step to make this value available to the script.
User avatar
jeeswg
Posts: 5292
Joined: 19 Dec 2016, 01:58
Location: UK

Re: Thread global variables and thread ID

16 Sep 2018, 05:26

- Here are 2 links that may be relevant. Cheers.

- Perhaps this if implemented, would solve your problem:
- I had suggested A_ThisHwnd and A_ThisIfWinCriteria (cf. A_ThisHotkey). To get info for the matching window when the hotkey was executed. (And from the hWnd you can get the PID.)
jeeswg's 3-item wish list (GUI class name+GUI no icon, A_ThisHwnd/A_ThisIfWinCriteria on hotkey launch, InputBox HFONT) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 13&t=26180

- Perhaps this would give you a temporary solution:
- I also worked on this to handle hotkeys and windows more thoroughly.
log hotkeys, get extended hotkey info, interact with the *right* window (Hotkey command with FunctionObject example) - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=29560
User avatar
nnnik
Posts: 3486
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Thread global variables and thread ID

16 Sep 2018, 06:34

I dont understand your problem could you post an example that showcases where your problem lies?
Recommends AHK Studio
2_05
Posts: 9
Joined: 09 May 2018, 10:28

Re: Thread global variables and thread ID

16 Sep 2018, 07:24

Working examples #A and #B. Take into account that while the thread is still active, the user may start a new thread on another Notepad window.

#A using passing trough the pid and #B using the last found window. In #A it may seem like a minor inconvenience to pass the pid. But with many different functions and functions with various inputs, some requiring pid and others don't, it soon becomes messy and difficult to maintain. In #B, OpenAbout needs to restore the last found window to ensure View Statusbar is triggered correctly.

In the proposed solution #C, pid is a thread global variable. It cannot be altered by another thread. There is no need to pass it trough and it is automatically destroyed at the end of the thread.

Code: Select all

SetTitleMatchMode, 2

#If pid := WinGet("ahk_id" WinActive("- Notepad"), "pid")
	#A:: openAboutPID(pid, 5000)
	#B:: openAboutLF(5000)
#If

openAboutPID(pid, nseconds)
{
	WinMenuSelectItem, - Notepad ahk_pid %pid%, , Help, About
	Sleep, %nseconds%
	closeAboutPID(pid)
	WinMenuSelectItem, - Notepad ahk_pid %pid%, , View, Status Bar
}

closeAboutPID(pid)
{
	WinClose, About Notepad ahk_pid %pid%
}

openAboutLF(nseconds)
{
	WinMenuSelectItem, , , Help, About
	Sleep, %nseconds%
	closeAboutLF()
	WinMenuSelectItem, , , View, Status Bar
}

closeAboutLF()
{
	lf := WinExist()
	WinGet, pid, pid
	WinClose, About Notepad ahk_pid %pid%
	WinExist("ahk_id " lf) ; Restore last found
}

WinGet(title, cmd := "")
{
	WinGet, output, %cmd%, %title%
	return output
}
How I want it (not working example)

Code: Select all

SetTitleMatchMode, 2

ThreadGlobal threadpid 

#If threadpid := WinGet("ahk_id" WinActive("- Notepad"), "pid")
	#C:: openAboutTG(5000)
#If

openAboutTG(nseconds)
{
	WinMenuSelectItem, - Notepad ahk_pid %threadpid%, , Help, About
	Sleep, %nseconds%
	closeAboutTG()
	WinMenuSelectItem, - Notepad ahk_pid %threadpid%, , View, Status Bar
}

closeAboutTG()
{
	WinClose, About Notepad ahk_pid %threadpid%
}

WinGet(title, cmd := "")
{
	WinGet, output, %cmd%, %title%
	return output
}
User avatar
nnnik
Posts: 3486
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Thread global variables and thread ID

16 Sep 2018, 08:00

Whats the problem with solution A?
You should avoid globals completely anyways.
Also your example is needlessly complex, the following would have been enough:

Code: Select all

#IfWinActive, ahk_exe Notepad.exe
	c:: triggerActionFor(5000, WinActive("A"))
#If

triggerStateFor(time, pid) {
	enterState(pid)  ;whatever you want to do
	Sleep %time%
	exitState(pid)    ;whatever you want to undo
}
ThreadLocal variables would be a bad solution here since you might rather want to use SetTimer for larger waiting times than Sleep %time%.
Or maybe something completely different like a scheduled task or whatever.
For those cases it's better when you deliver the information necessary to make your code the way its supposed to work.

Another option might be classes since you can essentially use the object like a local environment for your task.
But for things this small just passing the information as a parameter is the best option.
Recommends AHK Studio
2_05
Posts: 9
Joined: 09 May 2018, 10:28

Re: Thread global variables and thread ID

16 Sep 2018, 09:18

I see I may not have clarified my example enough. The sleep part represents a sequence of actions which take up several seconds, a time in which the user may start another thread which should also be possible. I also have to add that the script I wrote became quite large and I have already converted it to use classes, though still I'm thinking threadglobals can simplify the code and make it easier to maintain because I'm still have to pass pid when creating nested classes.

Note that in your code you are passing the hwnd of one of the windows of a process, though at some point that window itself may be destroyed while the process and its other windows keep on running.

Just consider a script with many functions with 3-6 inputs, some of which require the PID because they interact with windows, others do not. Or consider a script with classes, that have many nested classes. And no large waiting times but just a lot of window interaction which takes time to complete. There are ways to do without Threadglobals and it's true that objects can act like a local environment, I won't argue. I just think thread specific variables can make such code easier to write and easier to maintain.
User avatar
nnnik
Posts: 3486
Joined: 30 Sep 2013, 01:01
Location: Germany

Re: Thread global variables and thread ID

16 Sep 2018, 12:06

I think easier to write is true.
But to me they seem like a maintenance nightmare.
Also I dont see an issue with passing anything to subclasses.
Unless you made the whole code a mess there should only be one class that ever contains the PID and other classes contain specific hWNDs.
Recommends AHK Studio
2_05
Posts: 9
Joined: 09 May 2018, 10:28

Re: Thread global variables and thread ID

19 Sep 2018, 00:39

I would consider it a valuable tool and when implemented users can choose to use it or not.
I think maintenance wise thread globals would be similar to normal globals. As with the normal global variables, it is important to name variables in a way that makes it clear the variable is not local.

Return to “Wish List”

Who is online

Users browsing this forum: No registered users and 5 guests