blob: fb2ae21812c1324eac03bb5531a3457cba2e8a38 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:FDL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/
/*!
\example ipc/sharedmemory
\title Shared Memory Example
\ingroup examples-ipc
\brief Demonstrates doing inter-process communication using shared memory with
the QSharedMemory class.
The Shared Memory example shows how to use the QSharedMemory class
to implement inter-process communication using shared memory. To
build the example, run make. To run the example, start two instances
of the executable. The main() function creates an \l {QApplication}
{application} and an instance of our example's Dialog class. The
dialog is displayed and then control is passed to the application in
the standard way.
\snippet ipc/sharedmemory/main.cpp 0
Two instances of class Dialog appear.
\image sharedmemory-example_1.png Screenshot of the Shared Memory example
Class Dialog inherits QDialog. It encapsulates the user interface
and an instance of QSharedMemory. It also has two public slots,
loadFromFile() and loadFromMemory() that correspond to the two
buttons on the dialog.
\snippet ipc/sharedmemory/dialog.h 0
The constructor builds the user interface widgets and connects the
clicked() signal of each button to the corresponding slot function.
\snippet ipc/sharedmemory/dialog.cpp 0
Note that "QSharedMemoryExample" is passed to the \l {QSharedMemory}
{QSharedMemory()} constructor to be used as the key. This will be
used by the system as the identifier of the underlying shared memory
segment.
Click the \tt {Load Image From File...} button on one of the
dialogs. The loadFromFile() slot is invoked. First, it tests whether
a shared memory segment is already attached to the process. If so,
that segment is detached from the process, so we can be assured of
starting off the example correctly.
\snippet ipc/sharedmemory/dialog.cpp 1
The user is then asked to select an image file using
QFileDialog::getOpenFileName(). The selected file is loaded into a
QImage. Using a QImage lets us ensure that the selected file is a
valid image, and it also allows us to immediately display the image
in the dialog using setPixmap().
Next the image is streamed into a QBuffer using a QDataStream. This
gives us the size, which we then use to \l {QSharedMemory::}
{create()} our shared memory segment. Creating a shared memory
segment automatically \l {QSharedMemory::attach()} {attaches} the
segment to the process. Using a QBuffer here lets us get a pointer
to the image data, which we then use to do a memcopy() from the
QBuffer into the shared memory segment.
\snippet ipc/sharedmemory/dialog.cpp 2
Note that we \l {QSharedMemory::} {lock()} the shared memory segment
before we copy into it, and we \l {QSharedMemory::} {unlock()} it
again immediately after the copy. This ensures we have exclusive
access to the shared memory segment to do our memcopy(). If some
other process has the segment lock, then our process will block
until the lock becomes available.
Note also that the function does not \l {QSharedMemory::} {detach()}
from the shared memory segment after the memcopy() and
unlock(). Recall that when the last process detaches from a shared
memory segment, the segment is released by the operating
system. Since this process only one that is attached to the shared
memory segment at the moment, if loadFromFile() detached from the
shared memory segment, the segment would be destroyed before we get
to the next step.
When the function returns, if the file you selected was qt.png, your
first dialog looks like this.
\image sharedmemory-example_2.png Screenshot of the Shared Memory example
In the second dialog, click the \tt {Display Image From Shared
Memory} button. The loadFromMemory() slot is invoked. It first \l
{QSharedMemory::attach()} {attaches} the process to the same shared
memory segment created by the first process. Then it \l
{QSharedMemory::lock()} {locks} the segment for exclusive access and
links a QBuffer to the image data in the shared memory segment. It
then streams the data into a QImage and \l {QSharedMemory::unlock()}
{unlocks} the segment.
\snippet ipc/sharedmemory/dialog.cpp 3
In this case, the function does \l {QSharedMemory::} {detach()} from
the segment, because now we are effectively finished using
it. Finally, the QImage is displayed. At this point, both dialogs
should be showing the same image. When you close the first dialog,
the Dialog destructor calls the QSharedMemory destructor, which
detaches from the shared memory segment. Since this is the last
process to be detached from the segment, the operating system will
now release the shared memory.
*/