2011-10-14 13 views
5

Sto utilizzando Qt e sto cercando di ottenere un'applicazione a singola istanza applicando la soluzione this in Linux (ubuntu). Il problema è che se l'applicazione termina inaspettatamente (errore di divisione o utente lo uccide) la memoria condivisa rimane collegata e nessun altro processo può crearla nuovamente. Richiamo da QSharedMemory doc:Perdita di memoria condivisa in C++, come cancellare la memoria condivisa?

Unix: QSharedMemory "possiede" il segmento di memoria condivisa. Quando l'ultimo thread o processo con un'istanza di QSharedMemory collegata a un segmento di memoria condiviso specifico si stacca dal segmento per distruggendo l'istanza di QSharedMemory, il kernel Unix rilascia il segmento di memoria condivisa . Ma se l'ultimo thread o processo si blocca senza eseguire il distruttore QSharedMemory, il segmento di memoria condivisa sopravvive all'incidente.

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

    // Ensure single instanse of Cevirgec application 
    QSharedMemory shared(ApplicationConstants:: 

    if(!shared.create(512, QSharedMemory::ReadWrite)) 
    { 
     // QMessageBox msgBox; 
     QMessageBox::critical(0, QObject::tr("application is already running!"), QObject::tr("application is already running!"), QMessageBox::Ok, QMessageBox::Ok); 
     qCritical() << "application is already running!"; 

     exit(0); 
    } 
    else { 
     qDebug() << "application staring..."; 
    } 
    return a.exec(); 
} 

Quali soluzioni si può suggerire qui? Come posso assicurare che la memoria condivisa sia cancellata (o qualunque verbo usato in generale) dopo che il processo finisce. Ho bisogno di qualcosa come finally in Java tutto la funzione principale:/

EDIT: (Soluzione)

ho raggiunto il comportamento desiderato utilizzando QSharedMemory e la cattura del segnale SIGSEGV quindi chiamare sharedMemory.detach() in il gestore del segnale.

+0

Probabilmente non dovresti provare a realizzare un'app che si comporta in modo diverso da come il sistema operativo e gli utenti si aspettano che le app si comportino. Se il comportamento standard per il sistema operativo è tale che gli utenti si aspettano di essere in grado di avviare più istanze, come su Windows e Linux, dovrebbero essere in grado di farlo. Se il comportamento standard è quello di forzare una singola istanza, come nei Mac, quindi lasciare che il sistema operativo lo faccia da sé. – bames53

+2

beh, non esiste uno standard per tali comportamenti nei sistemi operativi. È totalmente dipendente dall'applicazione – destan

+0

bames53: ci sono tantissime app che ti permettono solo di avviare un'istanza, ea volte è la cosa più logica da fare. – rubenvb

risposta

4

È possibile rilevare i segnali che bloccano il programma e utilizzare un gestore che chiama il distruttore QSharedMemory.

+0

Posso chiamare manualmente un distruttore – destan

+0

Sì, ad es. per un oggetto f di classe Foo: 'f. ~ Foo();'. Ma devi farlo solo in circostanze in cui la lingua non chiamerà automaticamente il distruttore. – bames53

+0

Sì, è possibile - ma non so se si può dipendere da qualsiasi cosa legata al qt nel gestore di segnale, in quanto tali gestori dovrebbero essere autonomi e non relazionarsi su qualsiasi altra cosa nel programma. –

1

La verità è che se il tuo programma ha bisogno di essere ucciso o ha un segfault, allora non puoi davvero fare nulla al riguardo. La memoria condivisa non è la scelta migliore per garantire un'unica istanza di applicazione sotto UNIX/Linux. Prova invece a utilizzare i semafori, poiché vengono chiusi non appena termina l'applicazione.

EDIT:

dalla documentazione di sem_close

tutti aperti chiamato i semafori vengono automaticamente chiusi il processo terminazione, o su execve (2).

Devo anche aggiungere che garantire singolo-app contraint potrebbe avere conseguenze strane sul sistema come Linux - immaginare che qualcuno registrato tramite ssh con X tunneling e cercando di iniziare la vostra applicazione - se qualcuno sta già utilizzando, non lo farà inizio. Questo sarà piuttosto confisunig. Sei uno sviluppatore di applicazioni e dovresti sapere meglio se hai bisogno di un blocco per utente o per sessione di X per sessione.

Se si desidera utilizzare il blocco per utente, la soluzione potrebbe essere quella di aggiungere il file nascosto nella directory home dell'utente contenente il pid corrente. La prossima applicazione verificherà questo file, e se esiste AND/proc/[pid]/exe punta al binario corrente, quindi restituisce l'errore.

+0

Ma penso di aver bisogno di un semaforo a livello di sistema, giusto? – destan

+0

semafori Named per essere esatti –

+0

ma ci si pone lo stesso problema, se il semaforo è schiantato rimane acquisito – destan

1

Si può sempre eseguire uno script dopo la chiusura del programma per cancellare manualmente la memoria condivisa, i semafori, ecc. Sul proprio sistema (il mio è un Mac Pro con 10.8). Ho inserito uno script che uso per questo quando eseguo programmi che usano QSharedMemory e lo uso quando il programma si chiude in modo imprevisto e lascia le istanze di memoria condivisa "sospese".

Ricordare che in questo modo verranno rimosse tutte le istanze di memoria condivisa associate al proprio nome utente. Se sono in esecuzione più programmi e si utilizzano istanze di memoria condivisa, è necessario attendere fino a quando non viene eseguito qualsiasi programma o regolare lo script in base alle esigenze per eliminare solo le istanze di memoria condivisa create dal programma.

#!/bin/bash 

ME=$(whoami) 

IPCS_S=$(ipcs -s | grep $ME | sed "s///g" | cut -f2 -d " ") 
IPCS_M=$(ipcs -m | grep $ME | sed "s///g" | cut -f2 -d " ") 
IPCS_Q=$(ipcs -q | grep $ME | sed "s///g" | cut -f2 -d " ") 

echo "Clearing Semaphores" 
for id in $IPCS_S 
do 
    ipcrm -s $id 
done 

echo "Clearing Shared Memory" 
for id in $IPCS_M 
do 
    ipcrm -m $id 
done 

echo "Clearing Message Queues" 
for id in $IPCS_Q 
do 
    ipcrm -q $id 
done 
Problemi correlati