iOS: как узнать текущий язык приложения

Согласно документу 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 
    #include 
    #include 
    
    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 
    
    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.

20
задан gpopov 6 April 2012 в 16:09
поделиться