2012-05-21 8 views
5

Sto tentando di mostrare una schermata iniziale e di non bloccare l'applicazione mentre si connette a un database. Le connessioni normali (a MSSQL tramite ADO) richiedono circa 300 msec, e ciò non fa in modo che il thread principale mostri "non risponde" su Windows.Mostra una schermata iniziale mentre è in esecuzione una connessione al database (che potrebbe richiedere molto tempo)

Tuttavia, nel caso di (a) un errore di rete o (b) un errore di configurazione (nome host/istanza del server SQL non valido), occorrono 60 secondi per il timeout. Ciò non solo rende l'applicazione non reattiva, ma è quasi impossibile mostrare qualsiasi errore o messaggio quando si bloccherà. Potrei far apparire un messaggio prima di iniziare la connessione ma non c'è davvero alcuna soluzione quando il thread principale blocca per 60 secondi.

La soluzione sembra essere quella di spostare la connessione a un thread in background. Questo ha portato al seguente codice:

  1. un TThread di classe che rende il collegamento di fondo e alcuni SyncObj come un tID utilizzata per inviare un segnale al thread principale.

  2. Un ciclo nel thread principale con questo codice:

    BackgroundThread.StartConnecting; 
    while not BackgroundThread.IsEventSignalled do begin 
        Application.ProcessMessages; // keep message pump alive. 
    end; 
    // continue startup (reports error if db connection failed) 
    

E 'questa la strada giusta da percorrere? Le mie esitazioni riguardano i seguenti elementi della soluzione di cui sopra:.

A. sarei chiamando Application.ProcessMessages, che io considero un codice di odore estrema (Questo potrebbe essere un'eccezione ammessa a questa regola)

B. Sto introducendo i thread nell'avvio di un'applicazione, e sono preoccupato di introdurre bug.

Se qualcuno ha un'implementazione di riferimento che è noto per essere privi di condizioni di competizione, che può fare una connessione in background con ADO, ed è noto per essere un approccio sicuro, sarebbe davvero utile. In caso contrario, consigli generali o esempi parziali sono buoni.

+5

Dato che una connessione normale richiede solo 300ms, perché non modificare il timeout (ad esempio 1000 ms)? – awmross

+4

Come visualizzare la schermata iniziale dal thread in background: http: // StackOverflow.it/questions/388506/display-splash-screen-in-delphi-when-main-thread-is-busy – Harriv

+1

Questo problema è uno dei principali casi d'uso per mostrare l'interfaccia utente da un thread diverso dal thread principale della GUI –

risposta

4

A causa della nota limitazione che ogni thread deve utilizzare la propria connessione ADO (ovvero non è possibile utilizzare un oggetto di connessione creato in altro thread), l'unica opzione che posso pensare è creare un thread che effettui una connessione al database e, dopo aver stabilito la connessione o aver raggiunto il timeout, segnalare il thread principale relativo all'evento e chiudere/distruggere la connessione. Il thread principale può nel frattempo visualizzare splash o progresso, in attesa di un messaggio da quel thread. Quindi, elimini il caso con password errata o host non raggiungibile. È ragionevole supporre che, se il secondo thread potesse connettersi, il thread principale sarebbe in grado di connettersi subito dopo.

+0

+1, d'accordo, ma dovresti spostare tutte le azioni del database in quel thread, perché non puoi passare l'oggetto di connessione al thread principale da quello di lavoro. Ed è necessario averli in una discussione principale, ad es. nel caso in cui si utilizzano componenti di dati sensibili. – TLama

+1

Sta dicendo che apri solo e poi chiudi quella connessione. Quindi stai gestendo una connessione iniziale solo come una funzionalità di "controllo degli errori" della tua app. Devi ancora ripetere la logica di connessione nel thread principale. –

+0

@Warren, se stai solo verificando se è anche possibile connettersi e successivamente riconnettersi con le stesse impostazioni di connessione nel thread principale, allora potresti usare il codice dalla mia risposta cancellata (ora veramente cancellata). – TLama

1

Esistono diversi metodi per la comunicazione tra thread. Di solito uso i messaggi di Windows. Per prima cosa definisco il messaggio e il gestore di messaggi in un modulo. Quindi, quando ho bisogno di informare il thread principale da thread personalizzato, io uso la funzione PostMessage per inviare la notifica.

Piccolo tutorial here.

È anche possibile utilizzare la libreria per la filettatura, ad esempio OmniThreadLibrary.

+0

Lo so. BUt Mi chiedo in particolare di bloccare l'avvio della mia app - come faccio a farlo - il mio loop di pumping dei messaggi (chiamando i messaggi application.process) o qualcos'altro? –

+0

Ho finito per visualizzare la schermata iniziale nella discussione .. Vedi il link nel mio commento alla domanda. – Harriv