Running Psychopy window from a thread segfaults

394 views Asked by At

I'm trying to run my Psychopy window from a separate thread and control what's shown on it from another one, but all I get is Fatal Python error.

Here's a small example script that produces the same results as my larger one

from threading import Thread
from psychopy import visual, core
import time

class ThreadTest(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.text='Test'
        self.running = 1
        self.start()
        print 'doing stuff'

    def run(self):
        win = visual.Window()

        msg = visual.TextStim(win, text=self.text)
        while self.running:
            msg.setText(self.text)
            msg.draw()
            win.flip()
            print 'Drawing...'
            core.wait(2)

        win.close()
        print 'Stopping thread'

    def setText(self, text):
        self.text=text

    def stopTest(self):
        self.running = 0


def main():
    tt = ThreadTest()
    time.sleep(3)
    tt.setText('Test2')
    time.sleep(3)
    tt.stopTest()
    print 'Stopping main thread'

if __name__ == '__main__':
    main()

and the output

python testy.py 
doing stuff
Fatal Python error: (pygame parachute) Segmentation Fault
Aborted (core dumped)

This creates the Psychopy window but fails to show any te xt on it and then just crashes. I've also tried creating the window in __init__() but that didn't work either.

2

There are 2 answers

1
Jon On BEST ANSWER

This seems to be an issue with the text object, which come from pyglet and might interfere with pyglet threading. The code below actually works (to my amazement)!

BUT you're doing something that's strongly discouraged and not supported. OpenGL calls (that handle all the rendering) are not thread safe and shouldn't be called from anything other than the main thread.

Basically, you're on your own from here! ;-)

from threading import Thread
from psychopy import visual, core
import time

class ThreadTest(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.ori=0
        self.running = 1
        print 'initialised'

    def run(self):
        win = visual.Window()
        print 'created window'
        stim = visual.PatchStim(win)
        print 'created stim'
        while self.running:
            stim.ori = self.ori
            stim.draw()
            win.flip()
            print '.',
            core.wait(0.01)

        print 'Stopping auxil thread'

    def setOri(self, ori):
        self.ori=ori

    def stopTest(self):
        self.running = 0


def main():
    tt = ThreadTest()
    tt.start()
    for frameN in range(180):
        tt.setOri(frameN)
        time.sleep(0.01)
    tt.stopTest()
    print 'Stopping main thread'

if __name__ == '__main__':
    main()
1
Odingod On

The culprit was indeed the TextStim that wasn't in the mainloop. When I swapped the main and drawloops it started working. Now I just need to find a way to stop the new thread even if it's doing something.

from threading import Thread
from psychopy import visual, core
import time

class ThreadTest(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.text='Test'
        self.running = 1

        print 'doing stuff'

    def run(self):
        time.sleep(3)
        self.setText('Test2')
        time.sleep(3)
        self.stopTest()

    def mainloop(self):
        win = visual.Window()
        while self.running:

            msg = visual.TextStim(win)
            msg.setText(self.text)
            msg.draw()
            win.flip()
            print 'Drawing...'
            core.wait(2)
        win.close()
        print 'Stopping thread'

    def setText(self, text):
        self.text=text

    def stopTest(self):
        self.running = 0


def main():
    tt = ThreadTest()
    tt.start()
    tt.mainloop()
    print 'Stopping main thread'

if __name__ == '__main__':
    main()