McDermott-Group / servers

Public repo that stores LabRAD servers and other non-measurement related code
0 stars 2 forks source link

[mView/Device] Labrad Contexts with Threading #64

Closed nmGit closed 8 years ago

nmGit commented 8 years ago

When there are multiple devices connected to the same computer, labrad contexts can be used to switch between devices. However, this doesn't seem to be the case when using different contexts from different threads. Labrad appears to confuse the devices when they are being controlled by multiple threads.

The setup: -Multiple MKSPDR2000 devices -ONE labrad connection -THREE different contexts, one for each device.

What happens: -The readings for a single appears on another device, then another, then another...etc.

I managed to duplicate the problem with the script:

NOTE:

This does NOT work with threading, but DOES work without threading.

import labrad
import threading
# New labrad connection
cxn = labrad.connect()
# Get the context for this connection
ctx1 = cxn.context()
# Create instance of device
m = cxn.mks_pdr2000_server
# Select the device in the context we defined
m.select_device(0, context = ctx1)
# New context
ctx2 = cxn.context()
# Another device
m2 = cxn.mks_pdr2000_server
# Select another device in context 2
m2.select_device(1, context = ctx2)
# Store the outputs in text files
m1txt = open("m1.txt", "wb")
m2txt = open("m2.txt", "wb")
def askm1():
    for i in range(10):
        m1txt.write(str(i)+' '+str(m.get_pressure(context = ctx1))+'\n')
    threading.Timer(0.1, askm1).start()

def askm2():
    for i in range(10):
        m2txt.write(str(i)+' '+str(m2.get_pressure(context = ctx2))+'\n')
    threading.Timer(0.1, askm2).start()

m1thread = threading.Thread(target = askm1, args=[])
# If the main thread stops, stop the child thread
m1thread.daemon = True

m2thread = threading.Thread(target = askm2, args=[])
# If the main thread stops, stop the child thread
m2thread.daemon = True

m1thread.start()
m2thread.start()
roboguy222 commented 8 years ago

I can't get this to work. Are you coming in today?

roboguy222 commented 8 years ago

I'm not sure what the problem is. I am getting the following to work perfectly:

import labrad
import threading
import time

# New labrad connection
cxn = labrad.connect()
# Get two new contexts
ctx1 = cxn.context()
ctx2 = cxn.context()

# Create instance of device server
m = cxn.threading_test_server
# Select the device in the contexts we defined
m.select_device(0, context = ctx1)
m.select_device(1, context = ctx2)

m1txt = open("m1.txt", "wb")
m2txt = open("m2.txt", "wb")

def askm1():
    for i in range(10):
        m1txt.write(str(i)+' '+str(m.get_device(context = ctx1))+'\n')
    threading.Timer(0.9, askm1).start()

def askm2():
    for i in range(10):
        m2txt.write(str(i)+' '+str(m.get_device(context = ctx2))+'\n')
    threading.Timer(0.9, askm2).start()

m1thread = threading.Thread(target = askm1, args=[])
# If the main thread stops, stop the child thread
m1thread.daemon = True

m2thread = threading.Thread(target = askm2, args=[])
# If the main thread stops, stop the child thread
m2thread.daemon = True

print 'starting thread 1'
m1thread.start()
print 'starting thread 2'
m2thread.start()
time.sleep(15)

Test Server:

from labrad.server import LabradServer, setting
from labrad import units, util

class ThreadingTestServer(LabradServer):
    name = 'Threading Test Server'

    @setting(1, 'Select Device', device='v')
    def select_device(self, c, device):
        c['device'] = device

    @setting(2, 'Get Device', returns='v')
    def get_device(self, c):
        return c['device']

__server__ = ThreadingTestServer()

if __name__ == '__main__':
    from labrad import util
    util.runServer(__server__)
roboguy222 commented 8 years ago

Just to document here as well, the issue is blocking. See https://github.com/labrad/pylabrad/issues/279#issuecomment-238101214