# Where is this thread coming from?!?!?!?

**URL:** <https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569>\
**Category:** Ignition\
**Tags:** ignition81\
**Created:** [March 12, 2025, 11:39am UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569 "2025-03-12T11:39:04Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [March 12, 2025, 11:39am UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/1 "2025-03-12T11:39:04Z")

</div>

I have a lock that is locked with this thread:

`'gateway-tagchangescripts-project[PROJECT_NAME]-21'`

I don't have any gateway change script that call the function directly. All calls come from a `system.util.invokeAsync()` and should say `'script-invoke-async'`.

Someone knows where is coming from?

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 12, 2025, 12:30pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/2 "2025-03-12T12:30:03Z")

</div>

> [@danielps1818](#):
>
> I have a lock that is locked with this thread:

Can you elaborate on this? Share the stack trace or thread dump?

This is definitely a thread from a gateway tag change script in project "PROJECT\_NAME".

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [March 12, 2025, 1:09pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/3 "2025-03-12T13:09:18Z")

</div>

Yeah sorry.

I have some gateway tag changes that all call the same functions with `system.util.invokeAsync()`.

To fix the problem of the multiple executions we have a lock saved in `system.util.getGlobals()`. Each tag change script has it's own unique id.

This mean that the code will do something like this:

```python
lock_id = id # Id passed by param
lock = system.util.getGlobals().get(lock_id)

if not isinstance(lock, threading.Lock):
	system.util.getGlobals()[lock_id] = threading.Lock()
	lock = system.util.getGlobals().get(lock_id)

if not lock.acquire(False):
	return

```

However, sometimes whenever the code it's trying to enter the function the thread mentioned above it's blocking it.

Gateway tag change looks like this:

```python
system.util.invokeAsynchronous(
	main.logic,
	[
		"id1"
	],
	None,
	"id1 Script"
)

```

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 12, 2025, 1:15pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/4 "2025-03-12T13:15:44Z")

</div>

Share the stack trace / thread dump.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 12, 2025, 1:20pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/5 "2025-03-12T13:20:16Z")

</div>

Also, not sure if it's related yet or not, but this isn't thread safe like you're hoping:

```python
lock_id = id # Id passed by param
lock = system.util.getGlobals().get(lock_id)

if not isinstance(lock, threading.Lock):
	system.util.getGlobals()[lock_id] = threading.Lock()
	lock = system.util.getGlobals().get(lock_id)

if not lock.acquire(False):
	return

```

Two threads could trivially arrive inside the `isinstance` check at the same time and assign different lock instances or retrieve different lock instances depending on how execution played out from there.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 12, 2025, 2:01pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/6 "2025-03-12T14:01:09Z")

</div>

Consider _ **not** _ using locks, and _ **not** _ using `system.util.invokeAsynchronous()`. Put all of the tags that would use the same lock into the same list of tags in a gateway tag change event. Make as many gateway tag change events as you need. Each will run with one thread, with the least possible amount of contention. And you will avoid the cost of thread creation.

If you **must** use locks, you must `.setdefault` to set it up in globals. Also, always use `with` to safely acquire and release locks. (You may need `RLock` instead of `Lock`, too.)

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [March 12, 2025, 2:03pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/7 "2025-03-12T14:03:06Z")

</div>

> [@pturmel](#):
>
> If you **must** use locks, you must `.setdefault` to set it up in globals.

It should be as easy as this:

```python
lock = system.util.getGlobals().getMap() \
    .computeIfAbsent(lock_id, lambda _: threading.Lock())

```

but it's not, because for some reason globals is a `PyStringMap` (why????) that does not expose its internal `ConcurrentMap` ~~(though it looks like this changed in 8.3)~~.

edit: it has `getMap()`, not sure why it doesn't work 😕

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 12, 2025, 2:10pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/8 "2025-03-12T14:10:50Z")

</div>

> [@Kevin.Herron](#):
>
> (why????)

Because it must be compatible with Jython code module `globals()`. Gaining access to the single, JVM-wide legacy scope `globals()` is what `system.util.getGlobals()` was originally created to provide.

Anyways, jython code modules require PyStringMaps as identifier dictionaries. (Both `globals()` and `locals()`.) Those are keyed with jython identifiers, so other types of immutable keys are not acceptable.

Dropping legacy jython scope makes expanding the signature of `.getGlobals()` possible.

I normally write instantiation like so:

```python
from threading import RLock

# Fast Path
someLock = system.util.getGlobals().get('someLockId')

if not someLock:
	# Slow path. The RLock instance might be thrown away if threads
	# are racing
	someLock = system.util.getGlobals().setdefault('someLockId', RLock())

```

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [March 13, 2025, 3:27pm UTC](https://forum.inductiveautomation.com/t/where-is-this-thread-coming-from/103569/9 "2025-03-13T15:27:55Z")

</div>

Hi guys!

Thanks a lot for all the information and the help.  
We found the problem, but I'm going to study all your comments.

Some thing you said we can't really use because of our current project and our needs.

I **really** appreciate your help.  
I'll come back with whatever we end doing.

BR
