# "Critical sections" in Jython?

**URL:** <https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510>\
**Category:** Ignition\
**Tags:** scripting\
**Created:** [August 7, 2023, 11:18am UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510 "2023-08-07T11:18:56Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 11:18am UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/1 "2023-08-07T11:18:56Z")

</div>

I want to be able to log function calls for diagnosing issues by writing them with their args into a document tag.

I have everything working, but I notice sometimes that function calls are missing. The reason is that the logging is happening in multiple threads when multiple functions are called at the same time. Therefore, the document tag value is read and updated by more than one call, and the last to finish wins.

How would I implement something to fix this?

ChatGPT suggests `java.util.concurrent.locks.ReentrankLock`. I'll give it a go, but open to ideas

Context:  
I have 2x functions, the one that logs the function, ` __log_function_call`, and a wrapper, `log_function_call`, that wraps the log function. Functions to be logged call `log_function_call` but it's the `__ log_function_call` function that reads and writes to the document tag.

---

<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:** [August 7, 2023, 11:45am UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/2 "2023-08-07T11:45:13Z")

</div>

Fundamentally, this is handled in python using the `with` statement and a lock. (Old school would use a `try` - `finally` construct.) But in Ignition, script module life cycles make locks untrustworthy across projects and project edits, so you absolutely need to make a persistent lock with `system.util.getGlobals` and ensure it is only initialized once.

Once you do that, I recommend the script module that does this also maintain a persistent cache object of content of the document tag (initialization would be the only read of the tag), modifying the cache and writing the tag under the lock.

But I have to admit that I don't approve--you are re-inventing the wheel (the java logging system).

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 11:55am UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/3 "2023-08-07T11:55:20Z")

</div>

> [@pturmel](#):
>
> the java logging system

As in using `system.util.getLogger`?

The reason this is difficult to use is the limited (or lack of) formatting options. I want to present this in Perspective like this below which shows things like tag writes and if successful or not, function calls, what thread they were part of, and the args passed into the function, etc. so that I can track what happens when I press buttons, or tags change value from the PLC. This project has lots of moving parts, so it's incredibly useful to see this info. Using the system.util.getLogger, I would be struggling to read and interpret it all.

 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/6/b/6bcd04bd10b1d93a0a301fa8ad0d6446a7cfb9ae.png)  
 ![image](https://us1.discourse-cdn.com/inductiveautomation/original/3X/b/9/b9d5ecd489b122ce661467ce1488d7f5502b659a.png)

> [@pturmel](#):
>
> But in Ignition, script module life cycles make locks untrustworthy across projects and project edits, so you absolutely need to make a persistent lock with `system.util.getGlobals` and ensure it is only initialized once.

I'll look at this now, cheers!

> [@pturmel](#):
>
> Once you do that, I recommend the script module that does this also maintain a persistent cache object of content of the document tag (initialization would be the only read of the tag), modifying the cache and writing the tag under the lock.

I'm already doing this part, minus the lock bit

---

<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:** [August 7, 2023, 12:03pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/4 "2023-08-07T12:03:49Z")

</div>

I understand the motivation, and can't really argue that it isn't valuable.

If you are caching this in a script top-level object, are you sure you cannot just access the object from your UI instead of the document tag?

Jython lists and dictionaries are implemented with java thread-safe collections, and simple list `.append()` or dictionary insert should not corrupt your data. (Use `.pop()` to remove old items from the tail of a list.)

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:04pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/5 "2023-08-07T12:04:22Z")

</div>

> [@pturmel](#):
>
> so you absolutely need to make a persistent lock with `system.util.getGlobals` and ensure it is only initialized once.

Is this how I would do this, at the top of my module:

```auto
import threading
log_function_call__lock = system.util.getGlobals().setdefault('log_function_call__lock', threading.Lock())

```

Then to use it:

```auto
def fun():
    with log_function_call__lock:
        do_the_thing

```

?

Edit: I edited for posterity so people won't have to scroll and find the solution in amongst the thread

---

<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:** [August 7, 2023, 12:05pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/6 "2023-08-07T12:05:58Z")

</div>

> [@nminchin](#):
>
> do this

Yes. And something similar for the cache object itself.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:08pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/7 "2023-08-07T12:08:17Z")

</div>

Yep, that one's a bit less nice, since a document tag's read value must be converted into basic Py objects to actually make it useful:

```auto
LogFunctionCall_Value = system.tag.readBlocking(LOG_FUNCTION_CALL__TAGPATH)[0].value
LogFunctionCall_Value = shared.util.misc.copyAndSanitise(LogFunctionCall_Value) if LogFunctionCall_Value is not None else []

```

This is one reason I'd consider this

> [@pturmel](#):
>
> If you are caching this in a script top-level object, are you sure you cannot just access the object from your UI instead of the document tag?
> 
> Jython lists and dictionaries are implemented with java thread-safe collections, and simple list `.append()` or dictionary insert should not corrupt your data. (Use `.pop()` to remove old items from the tail of a list.)

This would also make it independent of tags at all which would be nice

---

<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:** [August 7, 2023, 12:11pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/8 "2023-08-07T12:11:21Z")

</div>

Note that my `objectScript()` expression function has a short-circuit for accessing script module top level objects that aren't callable--it will avoid the interpreter overhead and just return the object. An expression binding's `[]` operator can then extract items from that object without python.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:14pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/9 "2023-08-07T12:14:13Z")

</div>

Very nice 🙂

when using `with lock.lock()` with a try/except inside of it, or outside of it?, will an exception end the lock?

e.g.

```auto
try:
    with lck:
        stuff...
        raise ValueError('Oh no!')
except:
    print 'Oopsie!'

```

Will this unlock?

Or

```auto
with lck:
    try:
        stuff...
        raise ValueError('Oh no!')
    except:
        print 'Oopsie!'

```

Edit: I removed the `.lock()`

---

<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:** [August 7, 2023, 12:15pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/10 "2023-08-07T12:15:58Z")

</div>

Actually, just leave off the `.lock()` when using `with`. The statement will lock and release for you, including when exceptions occur.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:16pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/11 "2023-08-07T12:16:31Z")

</div>

Haha, I just noticed that and edited at the same time you replied.

So the context manager will just sit there waiting for the lock to be available if it's not? Is there a timeout?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:33pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/12 "2023-08-07T12:33:42Z")

</div>

Oh no  
`AttributeError: 'java.util.concurrent.locks.ReentrantLock' object has no attribute ' __exit__'`

Maybe i'll implement it myself with a wrapper for it

---

<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:** [August 7, 2023, 12:34pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/13 "2023-08-07T12:34:13Z")

</div>

Are you sure you need a re-entrant lock?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:36pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/14 "2023-08-07T12:36:31Z")

</div>

> [@pturmel](#):
>
> this is handled in python using the `with` statement and a lock

What did you mean by this? I presumed you meant a re-entrant lock (I don't know the difference)

Edit: I assume you mean a `threading.Lock`?

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 12:38pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/15 "2023-08-07T12:38:36Z")

</div>

Also, I keep getting this error:

```auto
ImportError: Error loading module util: ImportError: cannot import name _newFunctionThread

```

in the context of (simplified):

```auto
from java.util.concurrent.locks import ReentrantLock
lck = ReentrantLock()
def fn():
	with lck:
		shared.util.function() # <-- this fails with similar to the error above

```

Maybe I broke something...  
I get this also when I just try to `import threading`

```auto
Traceback (most recent call last):
  File "<input>", line 4, in <module>
  File "C:\Users\<username>\.ignition\cache\gwse_8088\C0\pylib\threading.py", line 8, in <module>
    from thread import _newFunctionThread
ImportError: cannot import name _newFunctionThread

```

Edit:  
I deleted the pylib folder in my cache and restarted Designer and it's working now.

Thanks as always, Phil  
PS. i've changed to use a `threading.Lock`

---

<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:** [August 7, 2023, 1:08pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/16 "2023-08-07T13:08:35Z")

</div>

> [@nminchin](#):
>
> i've changed to use a `threading.Lock`

That was going to be my next suggestion. `with` expects a **jython** context manager, which the jython `lock` provides.

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [August 7, 2023, 1:18pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/17 "2023-08-07T13:18:14Z")

</div>

Why don't you just set your own MDC keys & values, so you can play into the existing logging storage mechanisms and avoid the headaches? It's org.slf4j.MDC or some classname like that.

---

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [August 7, 2023, 1:23pm UTC](https://forum.inductiveautomation.com/t/critical-sections-in-jython/77510/18 "2023-08-07T13:23:56Z")

</div>

> [@paul-griffith](#):
>
> Why don't you just set your own MDC keys & values

Because "just" for me is a lot more work to try to understand, haha 😅 (and I didn't know that existed)
