Evgenii Legotckoi
Evgenii Legotckoi28 січня 2016 р. 11:11

Qt/C++ - Урок 043. Одна програма Qt - Запуск лише одного екземпляра програми

Дозвіл запуску лише одного екземпляра програми може бути необхідним для обмеження проблем з витоками пам'яті, або для усунення можливих проблем з конкуренцією двох екземплярів програми за ресурси, файли, база даних SQLite і т.д. Або якщо програма в принципі передбачає лише один екземпляр, використовуваний користувачем.

Для вирішення цього завдання можна використовувати два наступні способи:

  • З використанням QLockFile - коли створюється тимчасовий файл, який знищується при закритті програми. При цьому при запуску другого екземпляра програми відбувається перевірка на існування даного файлу і якщо файл вже створено одним відкритим екземпляром програми, другий екземпляр автоматично закривається;
  • З використанням QSystemSemaphore та QSharedMemory - в даному випадку створюється сегмент пам'яті, що розділяється, і робиться спроба приєднати його до існуючого сегменту за унікальним ідентифікатором. Якщо спроба приєднання пройшла успішно, один екземпляр програми вже створено. Відповідно, повідомляємо про це користувачеві та закриваємо програму. Якщо спроба приєднання пройшла безуспішно, то створюємо виділяємо сегмент пам'яті для програми і запускаємо перший екземпляр.

Весь подальший програмний код не виходитиме за межі main.cpp.

Single application з використанням QLockFile

У наведеному нижче коді в папці для тимчасових файлів під час запуску програми створюється Lock File , у разі невдалої спроби створення Lock File , програма вважає, що вже відкрито один екземпляр програми, повідомляє про це користувачеві і закривається.

*Примітка. Замініть на ваш ідентифікатор.

#include "widget.h"
#include <QApplication>
#include <QLockFile>
#include <QDir>
#include <QMessageBox>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QLockFile lockFile(QDir::temp().absoluteFilePath("lurity.lock"));

    /* Пытаемся закрыть Lock File, если попытка безуспешна в течение 100 миллисекунд,
     * значит уже существует Lock File созданный другим процессом.
     * Следовательно, выбрасываем предупреждение и закрываем программу
     * */
    if (!lockFile.tryLock(100))
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.setText("Приложение уже запущено.\n"
                       "Разрешено запускать только один экземпляр приложения.");
        msgBox.exec();
        return 1;
    }

    Widget w;
    w.show();

    return a.exec();
}

Single application з використанням QSystemSemaphore та QSharedMemory

У першому варіанті дано просте та зручне вирішення задачі з обмеження кількості запущених екземплярів Qt програми. Але рішення на QLockFile має недоліки в тому плані, що можуть бути проблеми з дозволами для користувача. А також, якщо ви хочете обмежити, запуск програми одним екземпляром на весь комп'ютер, не розрізняючи те, скільки сесій може бути запущено на ньому, то використання QLockFile також не забезпечить цю можливість.

QSharedMemory ж навпаки є розділяється всім користувачів одночасно, що працюють за комп'ютером. Тому, якщо один із користувачів запустив Вашу програму, то другий вже не зможе її запустити.

Але в даному варіанті необхідно не забувати про відмінності в роботі з пам'яттю, що розділяється, під різними платформами. У випадку з Windows, пам'ять, що розділяється, буде звільнена як при штатному завершенні програми, так і при аварійному завершенні. У випадку з Linux/Unix при аварійному при аварійному завершенні пам'ять звільнена не буде.

У наведеному нижче коді семафор використовується для вирішення проблеми перегонів у випадку з одночасним запуском декількох екземплярів однієї програми. Семафор створюється з лічильником, максимальне число якого дорівнює 1. При піднятті семафора, всі інші екземпляри програми вже не мають доступу до пам'яті, що розділяється, і відповідно один екземпляр повністю володіє ресурсами. Цей екземпляр перевіряє наявність запущеного іншого екземпляра програми за наявністю сегмента пам'яті, що розділяється, з ідентифікатором, що відповідає даному додатку. Примірник успішно запускається і створює сегмент пам'яті, що розділяється у разі, якщо не знайшов інформації про інший екземплярі програми. Після цього семафор опускається, даючи можливість іншим екземплярам програми спробувати запуститися.

*Примітка. Замініть і на ваші ідентифікатор.

#include "mainwindow.h"
#include <QApplication>
#include <QSystemSemaphore>
#include <QSharedMemory>
#include <QMessageBox>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QSystemSemaphore semaphore("<uniq id>", 1);  // создаём семафор
    semaphore.acquire(); // Поднимаем семафор, запрещая другим экземплярам работать с разделяемой памятью

#ifndef Q_OS_WIN32
    // в linux/unix разделяемая память не освобождается при аварийном завершении приложения,
    // поэтому необходимо избавиться от данного мусора
    QSharedMemory nix_fix_shared_memory("<uniq id 2>");
    if (nix_fix_shared_memory.attach())
    {
        nix_fix_shared_memory.detach();
    }
#endif

    QSharedMemory sharedMemory("<uniq id 2>");  // Создаём экземпляр разделяемой памяти
    bool is_running;            // переменную для проверки ууже запущенного приложения
    if (sharedMemory.attach())
    {                           // пытаемся присоединить экземпляр разделяемой памяти
                                // к уже существующему сегменту
        is_running = true;      // Если успешно, то определяем, что уже есть запущенный экземпляр
    } 
    else
    {
        sharedMemory.create(1); // В противном случае выделяем 1 байт памяти
        is_running = false;     // И определяем, что других экземпляров не запущено
    }
    semaphore.release();        // Опускаем семафор

    // Если уже запущен один экземпляр приложения, то сообщаем об этом пользователю
    // и завершаем работу текущего экземпляра приложения
    if (is_running)
    {
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.setText(QObject::trUtf8("Приложение уже запущено.\n"
                        "Вы можете запустить только один экземпляр приложения."));
        msgBox.exec();
        return 1;
    }

    MainWindow w;
    w.show();

    return a.exec();
}

Відеоурок

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

IscanderChe
  • 25 листопада 2018 р. 03:49

День добрый.
Подскажите, как с помощью этих примеров вместо вывода сообщения сделать активным окно запущенного экземпляра приложения?

Evgenii Legotckoi
  • 25 листопада 2018 р. 12:20

Добрый день!

С помощью API целевой системы придётся найти нужный процесс и открыть окно. Но придётся писать платформозависимый код. В случае Windows нужно смотреть, как с помощью WinAPI искать процессы и пытаться открыть их окна, если они есть. В случае Linux там ещё сложнее, или через XLib, или через DBus, но я не уверен, как именно это делается.

IscanderChe
  • 25 листопада 2018 р. 13:24

Понятно. Спасибо!

Коментарі

Only authorized users can post comments.
Please, Log in or Sign up
AD

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:50бали,
  • Рейтинг балів-4
m
  • molni99
  • 26 жовтня 2024 р. 01:37

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:80бали,
  • Рейтинг балів4
m
  • molni99
  • 26 жовтня 2024 р. 01:29

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат:20бали,
  • Рейтинг балів-10
Останні коментарі
i
innorwall14 листопада 2024 р. 19:03
Qt/C++ - Урок 060. Налаштування зовнішнього вигляду програми під час виконання I didnt have an issue work colors priligy dapoxetine 60mg revia cost uk August 3, 2022 Reply
i
innorwall14 листопада 2024 р. 11:42
Як скопіювати файли в Linux If only females relatives with DZ offspring were considered these percentages were 23 order priligy online uk
i
innorwall14 листопада 2024 р. 09:09
Qt/C++ - Підручник 068. Hello World за допомогою системи збирання CMAKE в CLion ditropan pristiq dosing With the Yankees leading, 4 3, Rivera jogged in from the bullpen to a standing ovation as he prepared for his final appearance in Chicago buy priligy pakistan
i
innorwall14 листопада 2024 р. 04:05
EVILEG-CORE. Використання Google reCAPTCHA 2001; 98 29 34 priligy buy
Тепер обговоріть на форумі
i
innorwall14 листопада 2024 р. 03:39
добавить qlineseries в функции priligy amazon canada 93 GREB1 protein GREB1 AB011147 6
i
innorwall11 листопада 2024 р. 10:55
Всё ещё разбираюсь с кешем. priligy walgreens levitra dulcolax carbs The third ring was found to be made up of ultra relativistic electrons, which are also present in both the outer and inner rings
9
9Anonim25 жовтня 2024 р. 09:10
Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…
ИМ
Игорь Максимов03 жовтня 2024 р. 04:05
Реализация навигации по разделам Спасибо Евгений!

Слідкуйте за нами в соціальних мережах