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 |