Exemplo n.º 1
0
    def respond(self, byteArray, meta=None):
        if not self.conn:
            return False
        self.log("Sending Response. dataType: {0}, renderId: {1}".format(
            meta.get("dataType"), meta.get("renderId")))
        obj = {"type": self.TYPE_RESPONSE, "meta": meta or {}}

        memKey = self.nextMemoryKey()
        obj["memoryKey"] = memKey
        # TODO: check that the memory segment is not used

        # store data in shared memory
        mem = QSharedMemory(memKey)
        if mem.isAttached():
            mem.detach()

        if not mem.create(len(byteArray)):
            self.log(mem.errorString())
            return False
        self.log("Shared memory created: {0}, {1} bytes".format(
            memKey, len(byteArray)))

        mem.lock()
        try:
            ctypes.memmove(int(mem.data()), byteArray, len(byteArray))
        finally:
            mem.unlock()

        self._mem[memKey] = mem

        self.conn.write(json.dumps(obj).encode("utf-8") + b"\n")
        self.conn.flush()
        return True
Exemplo n.º 2
0
class SharedApplication(QApplication):
    def __init__(self, *args, **kwargs):
        super(SharedApplication, self).__init__(*args, **kwargs)
        self._running = False
        key = "SharedApplication" + __version__
        self._memory = QSharedMemory(key, self)

        isAttached = self._memory.isAttached()
        print("isAttached", isAttached)
        if isAttached:  # 如果进程附加在共享内存上
            detach = self._memory.detach()  # 取消进程附加在共享内存上
            print("detach", detach)

        if self._memory.create(
                1) and self._memory.error() != QSharedMemory.AlreadyExists:
            # 创建共享内存,如果创建失败,则说明已经创建,否则未创建
            print("create ok")
        else:
            print("create failed")
            self._running = True
            del self._memory

    def isRunning(self):
        return self._running
Exemplo n.º 3
0
class Dialog(QDialog):
    """ This class is a simple example of how to use QSharedMemory.  It is a
    simple dialog that presents a few buttons.  Run the executable twice to
    create two processes running the dialog.  In one of the processes, press
    the button to load an image into a shared memory segment, and then select
    an image file to load.  Once the first process has loaded and displayed the
    image, in the second process, press the button to read the same image from
    shared memory.  The second process displays the same image loaded from its
    new location in shared memory.

    The class contains a data member sharedMemory, which is initialized with
    the key "QSharedMemoryExample" to force all instances of Dialog to access
    the same shared memory segment.  The constructor also connects the
    clicked() signal from each of the three dialog buttons to the slot function
    appropriate for handling each button.
    """
    def __init__(self, parent=None):
        super(Dialog, self).__init__(parent)

        self.sharedMemory = QSharedMemory('QSharedMemoryExample')

        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        self.ui.loadFromFileButton.clicked.connect(self.loadFromFile)
        self.ui.loadFromSharedMemoryButton.clicked.connect(self.loadFromMemory)

        self.setWindowTitle("SharedMemory Example")

    def loadFromFile(self):
        """ This slot function is called when the "Load Image From File..."
        button is pressed on the firs Dialog process.  First, it tests whether
        the process is already connected to a shared memory segment and, if so,
        detaches from that segment.  This ensures that we always start the
        example from the beginning if we run it multiple times with the same
        two Dialog processes.  After detaching from an existing shared memory
        segment, the user is prompted to select an image file.  The selected
        file is loaded into a QImage.  The QImage is displayed in the Dialog
        and streamed into a QBuffer with a QDataStream.  Next, it gets a new
        shared memory segment from the system big enough to hold the image data
        in the QBuffer, and it locks the segment to prevent the second Dialog
        process from accessing it.  Then it copies the image from the QBuffer
        into the shared memory segment.  Finally, it unlocks the shared memory
        segment so the second Dialog process can access it.  After self
        function runs, the user is expected to press the "Load Image from
        Shared Memory" button on the second Dialog process.
        """

        if self.sharedMemory.isAttached():
            self.detach()

        self.ui.label.setText("Select an image file")
        fileName, _ = QFileDialog.getOpenFileName(
            self, None, None, "Images (*.png *.xpm *.jpg)")
        image = QImage()
        if not image.load(fileName):
            self.ui.label.setText(
                "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Load into shared memory.
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image
        size = buf.size()

        if not self.sharedMemory.create(size):
            self.ui.label.setText("Unable to create shared memory segment.")
            return

        size = min(self.sharedMemory.size(), size)
        self.sharedMemory.lock()

        # Copy image data from buf into shared memory area.
        self.sharedMemory.data()[:] = buf.data().data()
        self.sharedMemory.unlock()

    def loadFromMemory(self):
        """ This slot function is called in the second Dialog process, when the
        user presses the "Load Image from Shared Memory" button.  First, it
        attaches the process to the shared memory segment created by the first
        Dialog process.  Then it locks the segment for exclusive access, copies
        the image data from the segment into a QBuffer, and streams the QBuffer
        into a QImage.  Then it unlocks the shared memory segment, detaches
        from it, and finally displays the QImage in the Dialog.
        """

        if not self.sharedMemory.attach():
            self.ui.label.setText(
                "Unable to attach to shared memory segment.\nLoad an "
                "image first.")
            return

        buf = QBuffer()
        ins = QDataStream(buf)
        image = QImage()

        self.sharedMemory.lock()
        buf.setData(self.sharedMemory.constData())
        buf.open(QBuffer.ReadOnly)
        ins >> image
        self.sharedMemory.unlock()
        self.sharedMemory.detach()

        self.ui.label.setPixmap(QPixmap.fromImage(image))

    def detach(self):
        """ This private function is called by the destructor to detach the
        process from its shared memory segment.  When the last process detaches
        from a shared memory segment, the system releases the shared memory.
        """

        if not self.sharedMemory.detach():
            self.ui.label.setText("Unable to detach from shared memory.")
Exemplo n.º 4
0
class Dialog(QDialog):
    """ This class is a simple example of how to use QSharedMemory.  It is a
    simple dialog that presents a few buttons.  Run the executable twice to
    create two processes running the dialog.  In one of the processes, press
    the button to load an image into a shared memory segment, and then select
    an image file to load.  Once the first process has loaded and displayed the
    image, in the second process, press the button to read the same image from
    shared memory.  The second process displays the same image loaded from its
    new location in shared memory.

    The class contains a data member sharedMemory, which is initialized with
    the key "QSharedMemoryExample" to force all instances of Dialog to access
    the same shared memory segment.  The constructor also connects the
    clicked() signal from each of the three dialog buttons to the slot function
    appropriate for handling each button.
    """

    def __init__(self, parent = None):
        super(Dialog, self).__init__(parent)

        self.sharedMemory = QSharedMemory('QSharedMemoryExample')

        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        self.ui.loadFromFileButton.clicked.connect(self.loadFromFile)
        self.ui.loadFromSharedMemoryButton.clicked.connect(self.loadFromMemory)

        self.setWindowTitle("SharedMemory Example")

    def loadFromFile(self):
        """ This slot function is called when the "Load Image From File..."
        button is pressed on the firs Dialog process.  First, it tests whether
        the process is already connected to a shared memory segment and, if so,
        detaches from that segment.  This ensures that we always start the
        example from the beginning if we run it multiple times with the same
        two Dialog processes.  After detaching from an existing shared memory
        segment, the user is prompted to select an image file.  The selected
        file is loaded into a QImage.  The QImage is displayed in the Dialog
        and streamed into a QBuffer with a QDataStream.  Next, it gets a new
        shared memory segment from the system big enough to hold the image data
        in the QBuffer, and it locks the segment to prevent the second Dialog
        process from accessing it.  Then it copies the image from the QBuffer
        into the shared memory segment.  Finally, it unlocks the shared memory
        segment so the second Dialog process can access it.  After self
        function runs, the user is expected to press the "Load Image from
        Shared Memory" button on the second Dialog process.
        """

        if self.sharedMemory.isAttached():
            self.detach()

        self.ui.label.setText("Select an image file")
        fileName, _ = QFileDialog.getOpenFileName(self, None, None,
                "Images (*.png *.xpm *.jpg)")
        image = QImage()
        if not image.load(fileName):
            self.ui.label.setText(
                    "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Load into shared memory.
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image
        size = buf.size()

        if not self.sharedMemory.create(size):
            self.ui.label.setText("Unable to create shared memory segment.")
            return

        size = min(self.sharedMemory.size(), size)
        self.sharedMemory.lock()

        # Copy image data from buf into shared memory area.
        self.sharedMemory.data()[:] = buf.data().data()
        self.sharedMemory.unlock()

    def loadFromMemory(self):
        """ This slot function is called in the second Dialog process, when the
        user presses the "Load Image from Shared Memory" button.  First, it
        attaches the process to the shared memory segment created by the first
        Dialog process.  Then it locks the segment for exclusive access, copies
        the image data from the segment into a QBuffer, and streams the QBuffer
        into a QImage.  Then it unlocks the shared memory segment, detaches
        from it, and finally displays the QImage in the Dialog.
        """

        if not self.sharedMemory.attach():
            self.ui.label.setText(
                    "Unable to attach to shared memory segment.\nLoad an "
                    "image first.")
            return
 
        buf = QBuffer()
        ins = QDataStream(buf)
        image = QImage()

        self.sharedMemory.lock()
        buf.setData(self.sharedMemory.constData())
        buf.open(QBuffer.ReadOnly)
        ins >> image
        self.sharedMemory.unlock()
        self.sharedMemory.detach()

        self.ui.label.setPixmap(QPixmap.fromImage(image))

    def detach(self):
        """ This private function is called by the destructor to detach the
        process from its shared memory segment.  When the last process detaches
        from a shared memory segment, the system releases the shared memory.
        """

        if not self.sharedMemory.detach():
            self.ui.label.setText("Unable to detach from shared memory.")
Exemplo n.º 5
0
class ProducerDialog(QDialog):
    def __init__(self, parent=None):
        super(ProducerDialog, self).__init__(parent)

        self.ui = Ui_Dialog()
        self.ui.setupUi(self)

        # We only allow one image to be put into the shared memory (otherwise we would need to
        # create a dedicated data structure within the SHARED memory and access it from Python and
        # C++ appropriately). Also note that "Open" and "Create" have very different semantics (see
        # docs) and we use "Create" to always create a "fresh" semaphore to not cause undesired
        # blocking/stalls, see also https://doc.qt.io/qt-5/qsystemsemaphore.html

        if CONSUMER == 0:
            self.ui.loadFromFileButton.clicked.connect(self.load_from_file)
            self.ui.loadFromSharedMemoryButton.setEnabled(False)
            self.setWindowTitle("Shared Memory Producer: Python Example")
            from prodcon_ipc.producer_ipc import ProducerIPC
            self.producer_ipc = ProducerIPC(UNIQUE_SHARED_MEMORY_NAME,
                                            SHARED_MEMORY_KEY_FILE)
        else:
            self.ui.loadFromSharedMemoryButton.clicked.connect(
                self.load_from_memory)
            self.ui.loadFromFileButton.setEnabled(False)
            self.setWindowTitle("Shared Memory Consumer: Python Example")
            from prodcon_ipc.consumer_ipc import ConsumerIPC
            self.consumer_ipc = ConsumerIPC(UNIQUE_SHARED_MEMORY_NAME,
                                            SHARED_MEMORY_KEY_FILE)

        if SHARED_STRUCT == 1:
            self.shmem_config = QSharedMemory('shared_struct_test')
            if self.shmem_config.isAttached() or self.shmem_config.attach():
                if self.shmem_config.lock():
                    counter, stop_flag, file_name = struct.unpack(
                        STRUCT_FORMAT, self.shmem_config.constData())
                    logzero.logger.debug(
                        "Shared memory struct read: counter=" + str(counter) +
                        ", stop_flag=" + str(stop_flag) + ", file_name=" +
                        file_name)
                    self.shmem_config.unlock()
                else:
                    logzero.logger.error("unable to lock " +
                                         self.shmem_config.key())
                # Note: if both processes detach from the memory, it gets deleted so that attach() fails. That's why we
                #       simply never detach (HERE). Depending on the app design, there may be a better solution.
                #self.shmem_config.detach()
            else:
                logzero.logger.error("unable to attach " +
                                     self.shmem_config.key())

    def load_from_file(self):  # producer slot
        self.ui.label.setText("Select an image file")
        file_name, t = QFileDialog.getOpenFileName(self, None, None,
                                                   "Images (*.png *.jpg)")
        if not file_name:
            return

        image = QImage()
        if not image.load(file_name):
            self.ui.label.setText(
                "Selected file is not an image, please select another.")
            return

        self.ui.label.setPixmap(QPixmap.fromImage(image))

        # Get the image data:
        buf = QBuffer()
        buf.open(QBuffer.ReadWrite)
        out = QDataStream(buf)
        out << image

        try:
            from prodcon_ipc.producer_ipc import ScopedProducer
            with ScopedProducer(self.producer_ipc, buf.size()) as sp:
                # Copy image data from buf into shared memory area:
                sp.data()[:sp.size()] = buf.data().data()[:sp.size()]
        except Exception as err:
            self.ui.label.setText(str(err))

        if SHARED_STRUCT == 1:
            # Read from shared memory, increase value and write it back:
            if self.shmem_config.isAttached() or self.shmem_config.attach():
                if self.shmem_config.lock():
                    counter, stop_flag, _ = struct.unpack(
                        STRUCT_FORMAT, self.shmem_config.constData())
                    data = struct.pack(STRUCT_FORMAT, counter + 1, stop_flag,
                                       str(os.path.basename(file_name)[:30]))
                    size = min(struct.calcsize(STRUCT_FORMAT),
                               self.shmem_config.size())

                    self.shmem_config.data()[:size] = data[:size]
                    self.shmem_config.unlock()
                    if stop_flag:  # stop producing?
                        logzero.logger.info(
                            "Consumer requested to stop the production.")
                        sys.exit(0)
                else:
                    logzero.logger.error("unable to lock " +
                                         self.shmem_config.key())
                #self.shmem_config.detach()
            else:
                logzero.logger.error("unable to attach " +
                                     self.shmem_config.key())

    def load_from_memory(self):  # consumer slot
        buf = QBuffer()
        ins = QDataStream(buf)
        image = QImage()

        if True:  # first variant (much simpler / shorter, more robust)
            try:
                from prodcon_ipc.consumer_ipc import ScopedConsumer
                with ScopedConsumer(self.consumer_ipc) as sc:
                    buf.setData(sc.data())
                    buf.open(QBuffer.ReadOnly)
                    ins >> image
            except Exception as err:
                self.ui.label.setText(str(err))

        else:  # second variant, using begin()...end() manually
            try:
                data = self.consumer_ipc.begin()
            except RuntimeError as err:
                self.ui.label.setText(str(err))
                return

            # Read from the shared memory:
            try:
                buf.setData(data)
                buf.open(QBuffer.ReadOnly)
                ins >> image
            except Exception as err:
                logzero.logger.error(str(err))

            try:
                self.consumer_ipc.end()
            except RuntimeError as err:
                self.ui.label.setText(str(err))
                return

        if not image.isNull():
            self.ui.label.setPixmap(QPixmap.fromImage(image))
        else:
            logzero.logger.error("Image data was corrupted.")