DiamondLightSource/pythonSoftIOC

Can't Put PV value from multiple Process

Closed this issue · 2 comments

Dear All,
I try to create some PVs using pythonSoftIOC, and also create an another process to get/put the defined PVs. The code runs successfully, but the results are not corrected!(The two PV's values should be same). And I open another terminal to get the PV values, their are just the initialized ones in the builder procedure.
I don't know way, and whether it is ok using the multiple process to get/put PVs. Thanks a lot for your help and suggestions!

The code:
image

The result of run test code:
image

The result from another terminal:
image

Best regards,
Jiyizi

I've never actually used pyepics, but I have reproduced your issue. I think the problem is that cothread doesn't work when multiprocessing Processes are spawned after it is imported. I'm not quite sure why. There are 2 possibilities:

  1. Use cothread.Spawn and cothread.catools.caget rather than multiprocessing.Process and epics.PV.get
  2. Move the multiprocessing call before iocInit, as this does an implicit import cothread
    An example of 1:
# Import the basic framework components.
from softioc import softioc, builder
import cothread
from cothread.catools import caput

# Set the record prefix
builder.SetDeviceName("MY-DEVICE-PREFIX")

# Create some records
ai = builder.aIn('AI', initial_value=5)
ao = builder.aOut('AO', initial_value=12.45, always_update=True,
                  on_update=lambda v: ai.set(v))

# Boilerplate get the IOC started
builder.LoadDatabase()
softioc.iocInit()

# Start processes required to be run after iocInit
def update():
    counter = 0
    while True:
        counter += 1
        caput("MY-DEVICE-PREFIX:AO", counter)
        cothread.Sleep(1)

cothread.Spawn(update)

# Finally leave the IOC running with an interactive shell.
softioc.interactive_ioc(globals())

An example of 2:

# Import the basic framework components.
from multiprocessing import Process
import time
from softioc import softioc, builder

def update():
    from epics import PV
    time.sleep(10)
    a = PV("MY-DEVICE-PREFIX:AO")
    # Why do you have to make this twice?
    a = PV("MY-DEVICE-PREFIX:AO")
    counter = 0
    while True:
        counter += 1
        a.put(counter)
        time.sleep(1)

p = Process(target=update)
p.daemon = True
p.start()

# Set the record prefix
builder.SetDeviceName("MY-DEVICE-PREFIX")

# Create some records
ai = builder.aIn('AI', initial_value=5)
ao = builder.aOut('AO', initial_value=12.45, always_update=True,
                  on_update=lambda v: ai.set(v))

# Boilerplate get the IOC started
builder.LoadDatabase()
softioc.iocInit()

# Finally leave the IOC running with an interactive shell.
softioc.interactive_ioc(globals())

Dear Coretl,
Thanks for your help! I have tried your suggestion, and it worked.
For me, the second method is preferred, since more CPUs can be used now.

Best regards,
Jiyizi