Одно приложение для обоих окон и linux [duplicate]

Посмотрите на этот пример:

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope,$http) {

    var getJoke = function(){
        return $http.get('http://api.icndb.com/jokes/random').then(function(res){
            return res.data.value;  
        });
    }

    getJoke().then(function(res) {
        console.log(res.joke);
    });
});

Как вы можете видеть, getJoke возвращает разрешенное обещание (оно разрешено при возврате res.data.value). Таким образом, вы ждете, пока запрос $ http.get не будет завершен, а затем выполнится console.log (res.joke) (как обычный асинхронный поток).

Это plnkr:

http://embed.plnkr.co/XlNR7HpCaIhJxskMJfSg/

32
задан Nejat 3 May 2015 в 04:02
поделиться

7 ответов

для linux:

// ----------------------------------

QProcess *m_prSystemCall;
m_prSystemCall = new QProcess();

QString Commnd = "pgrep  " + qApp->applicationDisplayName();
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
QString output(m_prSystemCall->readAllStandardOutput());
QStringList AppList = output.split("\n", QString::SkipEmptyParts);
qDebug() <<"pgrep out:"<<AppList;
for(int i=0;i<AppList.size()-1;i++)
{
    Commnd = "kill " + AppList.at(i);
    m_prSystemCall->start(Commnd);
    m_prSystemCall->waitForFinished(8000);
}

// --------------------------------------- ----------------

и для Windows:

#include <tlhelp32.h>
#include <comdef.h>

QString pName = qApp->applicationDisplayName();
pName += ".exe";
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (Process32First(snapshot, &entry) == TRUE)
{
    DWORD myPID =  GetCurrentProcessId();
    while (Process32Next(snapshot, &entry) == TRUE)
    {
        const WCHAR* wc = entry.szExeFile ;
        _bstr_t b(wc);
        const char* c = b;

        if (stricmp(c, pName.toStdString().c_str()) == 0)
        {
            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

            qDebug() <<"myPID: "<< myPID << "entry.th32ProcessID" << entry.th32ProcessID;
            if(myPID != entry.th32ProcessID)
                TerminateProcess(hProcess,0);
            QThread::msleep(10);
            CloseHandle(hProcess);
        }
    }

}

CloseHandle(snapshot);
0
ответ дан aminM 26 August 2018 в 11:16
поделиться

для Windows:

HANDLE g_app_mutex = NULL;

bool check_one_app_instance () {g_app_mutex = :: CreateMutex (NULL, FALSE, L "8BD290769B404A7816985M9E505CF9AD64"); // это любой другой ключ как строка if (GetLastError () == ERROR_ALREADY_EXISTS) {CloseHandle (g_app_mutex); return false; }

return true;

}

0
ответ дан andreyDev 26 August 2018 в 11:16
поделиться

Простое решение, которое делает то, что вы хотите. Без зависимости от сети (как QtSingleApplication) и без каких-либо накладных расходов.

Использование:

int main()
{
    RunGuard guard( "some_random_key" );
    if ( !guard.tryToRun() )
        return 0;

    QAppplication a(/*...*/);
    // ...
}

RunGuard.h

#ifndef RUNGUARD_H
#define RUNGUARD_H

#include <QObject>
#include <QSharedMemory>
#include <QSystemSemaphore>


class RunGuard
{

public:
    RunGuard( const QString& key );
    ~RunGuard();

    bool isAnotherRunning();
    bool tryToRun();
    void release();

private:
    const QString key;
    const QString memLockKey;
    const QString sharedmemKey;

    QSharedMemory sharedMem;
    QSystemSemaphore memLock;

    Q_DISABLE_COPY( RunGuard )
};


#endif // RUNGUARD_H

RunGuard.cpp

#include "RunGuard.h"

#include <QCryptographicHash>


namespace
{

QString generateKeyHash( const QString& key, const QString& salt )
{
    QByteArray data;

    data.append( key.toUtf8() );
    data.append( salt.toUtf8() );
    data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex();

    return data;
}

}


RunGuard::RunGuard( const QString& key )
    : key( key )
    , memLockKey( generateKeyHash( key, "_memLockKey" ) )
    , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) )
    , sharedMem( sharedmemKey )
    , memLock( memLockKey, 1 )
{
    memLock.acquire();
    {
        QSharedMemory fix( sharedmemKey );    // Fix for *nix: http://habrahabr.ru/post/173281/
        fix.attach();
    }
    memLock.release();
}

RunGuard::~RunGuard()
{
    release();
}

bool RunGuard::isAnotherRunning()
{
    if ( sharedMem.isAttached() )
        return false;

    memLock.acquire();
    const bool isRunning = sharedMem.attach();
    if ( isRunning )
        sharedMem.detach();
    memLock.release();

    return isRunning;
}

bool RunGuard::tryToRun()
{
    if ( isAnotherRunning() )   // Extra check
        return false;

    memLock.acquire();
    const bool result = sharedMem.create( sizeof( quint64 ) );
    memLock.release();
    if ( !result )
    {
        release();
        return false;
    }

    return true;
}

void RunGuard::release()
{
    memLock.acquire();
    if ( sharedMem.isAttached() )
        sharedMem.detach();
    memLock.release();
}
51
ответ дан Dmitry Sazonov 26 August 2018 в 11:16
поделиться

Поскольку QtSingleApplication относительно устарел и больше не поддерживается, я написал замену, названную SingleApplication .

Он основан на QSharedMemory и использует QLocalServer уведомлять родительский процесс о том, что новый экземпляр является нерестом. Он работает на всех платформах и совместим с Qt 5.

Полный код и документация доступны здесь .

2
ответ дан Itay Grudev 26 August 2018 в 11:16
поделиться

Я использую это решение на данный момент.

Однако у него есть недостаток, что программа может запускаться только один раз пользователем, даже если они одновременно регистрируются из нескольких мест.

singleinstance.h

#ifndef SINGLEINSTANCE_H
#define SINGLEINSTANCE_H

typedef enum {
    SYSTEM,
    SESSION,
} scope_t;

class SingleInstance
{
public:
    static bool unique(QString key, scope_t scope);
};

#endif // SINGLEINSTANCE_H

singleinstance.cpp

#include <QLockFile>
#include <QProcessEnvironment>

#include "singleinstance.h"

/**
 * @brief filename
 * @param key
 * @param scope
 * @return a fully qualified filename
 *
 * Generates an appropriate filename for the lock
 */
static QString filename(QString key, scope_t scope) {

    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    QString tmp = env.value("TEMP", "/tmp") + "/";
    QString user = env.value("USER", "alfio");


    QString r;                                                                                                                                                                         
    switch (scope) {                                                                                                                                                                   
        case SYSTEM:                                                                                                                                                                   
            r = tmp;                                                                                                                                                                   
            break;
        case SESSION:
            //FIXME this will prevent trabucco to run in multiple X11 sessions
            r = env.value("XDG_RUNTIME_DIR", tmp + user) + "/";
            break;
    }
    return r + key + ".lock";
}

/**
 * @brief SingleInstance::unique
 * @param key the unique name of the program
 * @param scope wether it needs to be system-wide or session-wide
 * @return true if this is the only instance
 *
 * Make sure that this instance is unique.
 */
bool SingleInstance::unique(QString key, scope_t scope) {
    QLockFile* lock = new QLockFile(filename(key, scope));
    bool r = lock->tryLock();
    if (!r)
        delete lock;
    return r;
}
0
ответ дан LtWorf 26 August 2018 в 11:16
поделиться

Вы можете использовать QSharedMemory с определенным ключом и проверить, можно ли создать общую память с этим ключом или нет. Если он не может его создать, то экземпляр уже запущен:

QSharedMemory sharedMemory;
sharedMemory.setKey("MyApplicationKey");

if (!sharedMemory.create(1))
{
    QMessageBox::warning(this, tr("Warning!"), tr("An instance of this application is running!") );

    exit(0); // Exit already a process running
}
4
ответ дан Nejat 26 August 2018 в 11:16
поделиться

Согласно документу Qt, приобретенный QSystemSemaphore не будет автоматически выпущен, если процесс выйдет из строя, не вызвав его деструктор в Unix-подобных операционных системах. Это может стать причиной тупика в другом процессе, пытающегося получить тот же семафор. Если вы хотите быть на 100% уверенным, что ваша программа правильно справляется с аварийными ситуациями, и если вы не настаиваете на использовании Qt, вы можете использовать другие механизмы блокировки, которые операционные системы автоматически освобождают, когда процесс умирает - например, lockf() и флаг O_EXLOCK, переданный в open(), которые упомянуты в . Как восстановить семафор, когда процесс, который уменьшил его до нуля, сработает? или flock() . На самом деле создание общей памяти больше не требуется, если используется flock(). Просто использовать flock() достаточно для защиты одного экземпляра приложения.

Если восстановление семафора от сбоев в Unix не имеет значения, я думаю, что RunGuard из ответа Дмитрия Сазонова все еще может несколько упрощается:

  1. Деструктор ~RunGuard() и RunGuard::release() может быть снят, поскольку QSharedMemory будет автоматически отсоединяться от сегмента разделяемой памяти после его уничтожения, как в документе Qt для QSharedMemory::~QSharedMemory(): «Деструктор очищает ключ, который заставляет объект разделяемой памяти отсоединяться от основного сегмента разделяемой памяти».
  2. RunGuard::isAnotherRunning() также может быть снята. Целью является эксклюзивное исполнение. Как отметил @Nejat, мы можем просто воспользоваться тем фактом, что в любой момент может быть создано не более одного сегмента разделяемой памяти для данного ключа, как в документе Qt для QSharedMemory::create(): «Если сегмент разделяемой памяти, идентифицированный ключ уже существует, операция attach не выполняется и возвращается false. "
  3. Если я правильно понимаю, цель объекта« fix »QSharedMemory в конструкторе - уничтожить сегмент разделяемой памяти, который выживает из-за предыдущего сбоя процесса, как в документе Qt: «Unix: ... Когда последний поток или процесс, имеющий экземпляр QSharedMemory, прикрепленный к определенному сегменту разделяемой памяти, отделяется от сегмента, уничтожая его экземпляр QSharedMemory, ядро ​​Unix выпускает сегмент разделяемой памяти. Но если этот последний поток или процесс выйдет из строя, не запуская деструктор QSharedMemory, сегмент разделяемой памяти сохранится после сбоя. ". Когда «fix» будет уничтожено, неявный detach() должен быть вызван его деструктором, и сегмент оставшихся разделяемых разделов, если он есть, будет выпущен.
  4. Не уверен, что QSharedMemory является потокобезопасным / безопасный процесс или нет. В противном случае код, относящийся к memLock, может быть удален, если управление потоком осуществляется внутренне с помощью QSharedMemory. С другой стороны, fix также должен быть защищен memLock, если безопасность является проблемой:
    RunGuard::RunGuard( const QString& key )
        : key( key )
        , memLockKey( generateKeyHash( key, "_memLockKey" ) )
        , sharedMemKey( generateKeyHash( key, "_sharedMemKey" ) )
        , sharedMem( sharedMemKey )
        , memLock( memLockKey, 1 )
    {
        memLock.acquire();
        {
            QSharedMemory fix( sharedMemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/
            fix.attach();
        }
        memLock.release();
    }
    
    , поскольку явные attach() и неявные detach() вызываются вокруг fix.
  5. Упрощенная версия RunGuard выглядит следующим образом: Использование:
    int main()
    {
        RunGuard guard( "some_random_key" );
        if ( !guard.tryToRun() )
            return 0;
    
        QAppplication a(/*...*/);
        // ...
    }
    
    runGuard.h:
    #ifndef RUNGUARD_H
    #define RUNGUARD_H
    
    #include <QObject>
    #include <QSharedMemory>
    #include <QSystemSemaphore>
    
    class RunGuard
    {
    
    public:
        RunGuard( const QString& key );
        bool tryToRun();
    
    private:
        const QString key;
        const QString memLockKey;
        const QString sharedMemKey;
    
        QSharedMemory sharedMem;
        QSystemSemaphore memLock;
    
        Q_DISABLE_COPY( RunGuard )
    };
    
    
    #endif // RUNGUARD_H
    
    runGuard.cpp:
    #include "runGuard.h"
    #include <QCryptographicHash>
    
    namespace
    {
    
        QString generateKeyHash( const QString& key, const QString& salt )
        {
            QByteArray data;
            data.append( key.toUtf8() );
            data.append( salt.toUtf8() );
            data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex();
            return data;
    }
    
    }
    
    RunGuard::RunGuard( const QString& key )
        : key( key )
        , memLockKey( generateKeyHash( key, "_memLockKey" ) )
        , sharedMemKey( generateKeyHash( key, "_sharedMemKey" ) )
        , sharedMem( sharedMemKey )
        , memLock( memLockKey, 1 )
    {
        QSharedMemory fix( sharedMemKey ); // Fix for *nix: http://habrahabr.ru/post/173281/
        fix.attach();
    }
    
    bool RunGuard::tryToRun()
    {
        memLock.acquire();
        const bool result = sharedMem.create( sizeof( quint64 ) );
        memLock.release();
        if ( !result )
            return false;
    
        return true;
    }
    
  6. Здесь есть возможное состояние гонки:
    bool RunGuard::tryToRun()
    {
        if ( isAnotherRunning() )   // Extra check
            return false;
                                                                   // (tag1)
        memLock.acquire();
        const bool result = sharedMem.create( sizeof( quint64 ) ); // (tag2)
        memLock.release();
        if ( !result )
        {
            release();                                             // (tag3)
            return false;
        }
    
        return true;
    }
    
    Рассмотрим сценарий: Когда текущий процесс ProcCur работает до (tag1), происходит следующее: (обратите внимание, что (tag1) находится вне защиты блокировки) Другой процесс ProcOther с использованием RunGuard начинает работать. ProcOther работает до (tag2) и успешно создает общую память. ProcOther сбой, прежде чем он называет release() в (tag3). ProcCur продолжает работать с (tag1). ProcCur работает до (tag2) и пытается создать общую память. Однако sharedMem.create() вернет false, потому что ProcOther оставили созданную. Как мы видим в документе QSharedMemory::create(): «Если сегмент разделяемой памяти, идентифицированный ключом, уже существует, операция attach не выполняется и возвращается false». Наконец, RunGuard::tryToRun() в ProcCur вернет false, что не так ожидаемо, потому что ProcCur является единственным существующим процессом, использующим RunGuard.
-1
ответ дан Toby Speight 26 August 2018 в 11:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: