1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 <2021> 2022 2023 2024 | Index | 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 <2021> 2022 2023 2024 |
<== Date ==> | <== Thread ==> |
---|
Subject: | Weird channel access problem within Python softioc process |
From: | Paul Richards via Tech-talk <tech-talk at aps.anl.gov> |
To: | "tech-talk at aps.anl.gov" <tech-talk at aps.anl.gov> |
Date: | Wed, 11 Aug 2021 00:05:59 +0000 |
All, At Keck, we have been using the EPICS Python softioc with great success. The recent 3.1 release has made it even more popular and easier to use. That said, I have found a very odd behavior that I can replicate, relating to the consumption of keywords inside the same process that runs the softioc. Sometimes it makes sense to do it this way, instead
of finding a reference to the channel in the IOC and manipulating that. A simplified example of the problem:
Today I found a “solution” to this that does not make sense: if I start the softioc (the call to softioc.iotInit()) in the first thread, and not in the main process, everything works as expected. Our engineers are unable to explain this behavior. I hope there’s someone here on the list that might know why! Example code that demonstrates the failure: -------------------- import os import time import threading os.environ['EPICS_CA_SERVER_PORT'] = '5100' os.environ['EPICS_CA_ADDR_LIST'] = 'localhost:5100' os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'NO' try: import epicscorelibs.path.pyepics except ImportError: pass import epics from softioc import softioc, builder # Create a long record for this demo long = builder.longOut('prefix:long', initial_value=1) builder.LoadDatabase() softioc.iocInit() def thread1(): while True: val = long.get() long.set(val + 1) print(f'thread1: {val}') time.sleep(1) def thread2(): pv = epics.PV('prefix:long') while True: val = pv.get() print(f'thread2: {val}') time.sleep(1) t1 = threading.Thread(target=thread1, daemon=True) t2 = threading.Thread(target=thread2, daemon=True) t1.start() t2.start() time.sleep(10) Example that works; note the only change is the movement of the .iocInit() line down into thread1: -------------------- import os import time import threading os.environ['EPICS_CA_SERVER_PORT'] = '5100' os.environ['EPICS_CA_ADDR_LIST'] = 'localhost:5100' os.environ['EPICS_CA_AUTO_ADDR_LIST'] = 'NO' try: import epicscorelibs.path.pyepics except ImportError: pass import epics from softioc import softioc, builder # Create a long record for this demo long = builder.longOut('prefix:long', initial_value=1) builder.LoadDatabase() def thread1(): softioc.iocInit() while True: val = long.get() long.set(val + 1) print(f'thread1: {val}') time.sleep(1) def thread2(): pv = epics.PV('prefix:long') while True: val = pv.get() print(f'thread2: {val}') time.sleep(1) t1 = threading.Thread(target=thread1, daemon=True) t2 = threading.Thread(target=thread2, daemon=True) t1.start() t2.start() time.sleep(10) The output when it fails: $ python3 ./demoFailingDaemon.py Starting iocInit ############################################################################ ## EPICS 7.0.6.0 ## Rev. 7.0.6.99.1.0 ############################################################################ iocRun: All initialization complete thread1: 1 thread1: 2 thread1: 3 thread2: None thread1: 4 thread1: 5 thread2: None thread1: 6 thread1: 7 thread1: 8 thread2: None thread1: 9 thread1: 10 thread1: 11 The output when it works: $ python3 ./demoWorkingDaemon.py Starting iocInit ############################################################################ ## EPICS 7.0.6.0 ## Rev. 7.0.6.99.1.0 ############################################################################ iocRun: All initialization complete thread1: 1 thread2: 2 thread1: 2 thread2: 3 thread1: 3 thread2: 4 thread1: 4 thread2: 5 thread1: 5 thread2: 6 thread1: 6 thread2: 7 thread1: 7 thread2: 8 thread1: 8 thread2: 9 thread1: 9 thread2: 10 thread1: 10 thread2: 11 Paul
|