Crash when inserting text into a TextBuffer

I am using the following code to insert text in a TextBuffer:

class LogReader(threading.Thread):
    path = "/tmp/vortex-remote-log"
    def __init__(self, buffer):
        self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        self.socket.connect(self.path)
        self.do_run = True
        self.buffer = buffer
        super().__init__(None, None, f"monitor-log-thread-{self.socket.fileno()}")

    def run(self):
        while self.do_run:
            try:
                data = self.socket.recv(1024)
            except ConnectionResetError:
                break
            if not data:
                break
            self.buffer.insert_at_cursor(data.decode())

    def stop(self):
        self.do_run = False
        self.socket.close()

This does work when the volume of data is small and updates are slow. However, when I turn up the debug level of my application and the volume jumps up, the code crashes with the following error:

(python3:943098): Gtk-WARNING **: 16:27:54.532: Invalid text buffer iterator: either the iterator is uninitialized, or the characters/paintables/widgets in the buffer have been modified since the iterator was created.
You must use marks, character numbers, or line numbers to preserve a position across buffer modifications.
You can apply tags and insert marks without invalidating your iterators,
but any mutation that affects 'indexable' buffer contents (contents that can be referred to by character offset)
will invalidate all outstanding iterators
Segmentation fault (core dumped)

By my reading of the documentation, TextBuffer.insert_at_cursor() should be updating the cursor internally so it shouldn’t be invalid.

I also double checked that there isn’t another thread for some reason interfering.

What could be wrong?

Actually, it was the obvious answer that I had forgotten. I modified the code to use GLib.idle_add(callback, data) so the text insertion happens in the main thread and the text buffer started working.

Hi,

Yes correct, Gtk widgets can only be modified from the main thread, GLib.idle_add() is a good solution for that.

I also suggest to use a thread-safe Event instead of a boolean to check the exit condition:

class LogReader(threading.Thread):
    def __init__(self, buffer):
        self.do_stop = threading.Event()

    def run(self):
        while not self.do_stop.is_set():
            ...

    def stop(self):
        self.do_stop.set()