| Home |
This example demonstrates how to use QtSharedMemory to access a block of shared memory between processes.
factory.h:
/****************************************************************************
**
** Copyright (C) 2003-2007 Trolltech ASA. All rights reserved.
**
** This file is part of a Qt Solutions component.
**
** Licensees holding a valid Qt Solutions License Agreement may use this
** file in accordance with the rights, responsibilities, and obligations
** contained therein. Please consult your licensing agreement or contact
** [email protected] if any conditions of this licensing are not clear
** to you.
**
** Further information about Qt Solutions licensing is available at:
** http://www.trolltech.com/products/qt/addon/solutions/
** or by contacting [email protected].
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#ifndef FACTORY_H
#define FACTORY_H
#include <qtsharedmemory.h>
#include <QObject>
#include <QString>
class Worker {
public:
inline Worker(const QString &key, int count) { k = key; cnt = count; }
void start();
private:
QString k;
int cnt;
};
class Factory : public QObject
{
Q_OBJECT
public:
Factory(const QString &argv0, int workers);
~Factory();
void startCounting();
public slots:
void decreaseProcessCounter();
void checkStatus();
private:
int processCounter;
int nworkers;
int lastValue;
QtSharedMemory sharedMemory;
QString argv0;
};
#endif
factory.cpp:
/****************************************************************************
**
** Copyright (C) 2003-2007 Trolltech ASA. All rights reserved.
**
** This file is part of a Qt Solutions component.
**
** Licensees holding a valid Qt Solutions License Agreement may use this
** file in accordance with the rights, responsibilities, and obligations
** contained therein. Please consult your licensing agreement or contact
** [email protected] if any conditions of this licensing are not clear
** to you.
**
** Further information about Qt Solutions licensing is available at:
** http://www.trolltech.com/products/qt/addon/solutions/
** or by contacting [email protected].
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "factory.h"
#include <qstringlist.h>
#include <qprocess.h>
#include <qtimer.h>
#include <qtsharedmemory.h>
#include <qapplication.h>
#include <stdlib.h>
/*
Constructs a factory with \a nworkers workers, each working in its
own process. Each worker gets a share of the job of counting to
1000000. Adjusting the number of workers may change the overall
time spent to reach the number 1000000.
All counting is synchronous across processes.
*/
Factory::Factory(const QString &argv0, int workers)
: sharedMemory("Shared memory segment used for counting")
{
nworkers = workers;
this->argv0 = argv0;
}
/*
Creates the shared memory segment and starts the workers. Waits
for all workers to detach from the segment, then destroys it.
*/
void Factory::startCounting()
{
if (sharedMemory.exists())
sharedMemory.destroy(QtSharedMemory::ForceNoWait);
if (!sharedMemory.create(16)) {
qFatal("Unable to create shared memory: %s",
sharedMemory.errorString().toLatin1().constData());
return;
}
qDebug("Starting count to 1000000 using %i processes", nworkers);
processCounter = nworkers;
int cnt = 1000000;
int share = cnt / nworkers;
for (int i = 0; i < nworkers; ++i) {
if (i == nworkers - 1) share = cnt;
QStringList args;
args << "0";
args << QString::number(share);
QProcess *proc = new QProcess(this);
connect(proc, SIGNAL(finished(int)), SLOT(decreaseProcessCounter()));
proc->start(argv0, args);
cnt -= share;
}
lastValue = 0;
QTimer::singleShot(0, this, SLOT(checkStatus()));
}
void Factory::checkStatus()
{
// wait until the threads have started.
if (processCounter > 0) {
if (!sharedMemory.lock() || !sharedMemory.attach()) {
qDebug("The factory was unable to attach to the segment: %s",
sharedMemory.errorString().toLatin1().constData());
return;
}
int value = *(int *)sharedMemory.data();
qDebug("Progress: %7i/%7i | %3i%% | %7i/sec", value, 1000000, value * 100 / 1000000,
(value - lastValue));
lastValue = value;
if (!sharedMemory.detach()) {
qDebug("The factory was unable to detach from the segment: %s",
sharedMemory.errorString().toLatin1().constData());
sharedMemory.unlock();
return;
}
sharedMemory.unlock();
QTimer::singleShot(1000, this, SLOT(checkStatus()));
} else {
if (sharedMemory.lock() && sharedMemory.attach()) {
int value = *(int *)sharedMemory.data();
qDebug("Progress: %7i/%7i | %3i%% | %7i/sec", value, 1000000, value * 100 / 1000000,
(value - lastValue));
lastValue = value;
sharedMemory.detach();
sharedMemory.unlock();
}
if (!sharedMemory.destroy())
qDebug("Failed to destroy the segment: %s",
sharedMemory.errorString().toLatin1().constData());
qApp->quit();
}
}
void Factory::decreaseProcessCounter()
{
--processCounter;
}
/*
Waits until all threads have finished, then destructs the factory.
*/
Factory::~Factory()
{
}
/*
A worker increments the first integer of the shared memory segment
by one, cnt times. It does this in a locked region to avoid race
conditions which are very likely to occur here.
*/
void Worker::start()
{
// Initialize and attach to the shared memory segment
QtSharedMemory mem(k);
if (!mem.attach()) {
qDebug("A worker failed to attach: %s", mem.errorString().toLatin1().constData());
exit(0);
}
// Loop cnt times, incrementing the first int value in the shared
// memory segment in a locked region.
for (int i = 0; i < cnt; ++i) {
if (!mem.lock()) {
qDebug("A worker failed to lock the segment: %s",
mem.errorString().toLatin1().constData());
mem.unlock();
break;
}
// A sequence of operations that is likely to cause
// unsynchronized access to break.
volatile int *array = (int *) mem.data();
volatile int a = array[0];
++a;
array[0] = a;
mem.unlock();
}
if (!mem.detach())
qDebug("A worker failed to detach: %s", mem.errorString().toLatin1().constData());
}
main.cpp:
/****************************************************************************
**
** Copyright (C) 2003-2007 Trolltech ASA. All rights reserved.
**
** This file is part of a Qt Solutions component.
**
** Licensees holding a valid Qt Solutions License Agreement may use this
** file in accordance with the rights, responsibilities, and obligations
** contained therein. Please consult your licensing agreement or contact
** [email protected] if any conditions of this licensing are not clear
** to you.
**
** Further information about Qt Solutions licensing is available at:
** http://www.trolltech.com/products/qt/addon/solutions/
** or by contacting [email protected].
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include "factory.h"
#include <qapplication.h>
int main(int argc, char *argv[])
{
QApplication app(argc, argv, false);
if (argc < 2) {
qDebug("Usage: %s <nprocs>", argv[0]);
qDebug("Counts to 1000000 using nprocs processes");
return 1;
}
if (argc == 2) {
Factory *f = new Factory(argv[0], QString(argv[1]).toInt());
f->startCounting();
return app.exec();
} else {
Worker w("Shared memory segment used for counting",
QString(argv[2]).toInt());
w.start();
qDebug("Worker is done!");
return 0;
}
};
threadcounter.pro:
TEMPLATE = app
CONFIG -= moc
CONFIG += thread debug console
INCLUDEPATH += .
include(../../src/qtsharedmemory.pri)
# Input
SOURCES += main.cpp factory.cpp
HEADERS += factory.h
| Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies) | Trademarks | Qt Solutions |