2015-09-22 2 views
0

`m en utilisant Delphi XE6 et UniDAC et MySQLActualiser requêtes dans Threads

J'ai quelques composants TUniQuery dans mon DM et je veux Actualisez le thème à plusieurs reprises, donc je mets des minuteries dans ma principale forme et dans chaque minuterie Je crée un fil et passer une requête pour des données rafraîchissante:

pour l'exemple:

TUpdateThread = class(TThread) 
private 
    FQuery : TUniQuery; 
    FResultHandle : THandle; 
public 
    constructor Create(var Query : TUniQuery; ResultHandle : THandle); 
protected 
    procedure Execute; override; 
end; 

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle); 
begin 
inherited Create; 
Suspend; 
FQuery := Query; 
FResultHandle := ResultHandle; 
FreeOnTerminate := True; 
Resume; 
end; 

procedure TUpdateThread.Execute; 
var 
Msg : String; 
B : Boolean; 
begin 
try 
    B := True; 
    try 
    FQuery.Refresh; 
    except 
    on E:Exception do 
    begin 
    B := False; 
    Msg := 'Error : ' + #13 + E.Message; 
    SendMessage(FResultHandle, MSG_UPDATERESULT, 2, Integer(Msg)); 
    end; 
    end; 
finally 
    if B = True then 
    SendMessage(FResultHandle, MSG_UPDATERESULT, 1, 1); 

    Terminate; 
end; 
end; 

Parfois, il s `fait avec succès, mais plusieurs fois je suis arrivé quelques erreurs telles que ou AVs « net pack de tête. .. "erreur ou parfois j'ai proble m dans mes grilles (Ehlib DBGrid) comme une erreur dans les lignes de dessin ou ... (spécialement quand j'utilise DisableControls et EnableControls) Toutes les requêtes ont la même connexion, je pense que chaque thread doit avoir sa propre connexion, à cause de tous les intervalles de temporisation sont les mêmes, je suggère des requêtes parfois rafraîchissantes les interruptions les uns des autres

en fait, ma base de données est un serveur VPS et il y a des applications clientes, je veux avoir en direct-tables dans les clients et le thème de la mise à jour à plusieurs reprises

Qu'est-ce que est le meilleur moyen d'y parvenir? comment je devrais mettre à jour mes tables sans application se bloque! il y a quelques composants comme TThreadTimer (ou ...), le thème est-il utile pour cette situation?!

... merci

+3

N'utilisez pas de suspension/reprise. Ces méthodes sont obsolètes.Au lieu de cela, créez le thread suspendu et lancez-le lorsque l'initialisation est terminée. – Johan

+2

N'envoyez pas 'SendMessage' depuis votre thread. Considérez ce qui se passe si le récepteur est bloqué sur son traitement. Utilisez 'PostMessage' ou' SendMessageTimeout' pour vous assurer que votre thread ne mourra pas sur cette ligne. C'est pourquoi 'Synchronize' n'est pas implémenté comme un simple appel de fonction. – TLama

+0

@TLama: mais PostMessage a envoyé un message dans la file d'attente messae et avoir du retard! , plusieurs fois quand je crée un fil, je montre une fenêtre en attente et il n'y a pas de travail jusqu'à ce que le message arrive –

Répondre

1

La première question est ici:

constructor TUpdateThread.Create(var Query: TUniQuery; ResultHandle : THandle); 
begin 
inherited Create; // Create with no arguments 
Suspend;   // means CreateSuspended = false 
FQuery := Query; 
FResultHandle := ResultHandle; 
FreeOnTerminate := True; 
Resume; 
end; 

Ici vous créez le fil avec le constructeur par défaut (CreateSuspended = false) où le fil commence à courir immédiatement. Vous appelez suspend (qui est obsolète et ne doit pas être utilisé) immédiatement, mais il s'agit toujours d'une condition de concurrence puisque votre thread peut commencer ou ne pas commencer à essayer de répondre à votre requête avant de l'avoir affectée. Pour créer le fil dans un état suspendu utiliser le constructeur de surcharge de

inherited Create(true); 

Resume est également dépréciée. Au lieu de cela, vous devez utiliser Start;.

En outre, vous passez un TUniQuery au constructeur de ce thread. Nous pouvons supposer, je suppose, que cette requête a une affinité avec le thread principal - c'est-à-dire qu'elle est (peut-être) un composant visuel sur un formulaire, a des liens vers des composants visuels ou est interagi avec l'utilisateur ou l'utilisateur interface. La réponse, si c'est le cas, est que vous ne pouvez tout simplement pas faire cela - un thread ne peut pas modifier un objet ayant une affinité avec un autre thread. Votre interface peut être en train de récupérer des enregistrements de la requête lorsque le thread d'arrière-plan, par exemple, les détruit simultanément en vue d'actualiser le contenu de la requête. Naturellement, cela causera toutes sortes de problèmes.

La solution simple consiste à utiliser une minuterie régulière et à actualiser de manière synchrone sur le thread principal. Si cela prend trop de temps, vous devez envisager une stratégie différente. Nous n'avons pas vraiment assez d'informations pour suggérer beaucoup plus loin. Si l'accès au réseau et les E/S constituent le goulot d'étranglement, vous pouvez envisager d'actualiser de manière asynchrone un objet de requête distinct appartenant au thread, puis l'affecter de manière synchrone à vos composants de vue.

+0

En d'autres termes, créez et initialisez UniQuery à l'intérieur du thread, et à la fin du fil, remettez le UniQuery au formulaire. Dans ce cas, vous devez simplement passer le SQLtext au thread comme paramètre. – Johan

+1

Il est peut-être utile de mentionner que ClientDataSets fournit un moyen simple de transférer des données entre un thread de travail et le thread VCL, en affectant la propriété CDS Data du thread de travail. – MartynA

+0

J'ai essayé d'utiliser Start, mais quand je crée un thread une erreur affichée: "ne peut pas appeler Démarrer dans un thread en cours d'exécution ou suspendu", que se passe-t-il?! –