Précédent   Forum des professionnels en informatique > Logiciels > Microsoft Office > Access > VBA Access
VBA Access Le forum pour les questions relatives au code VBA sous Access, et à son environnement de développement VBE.
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 26/11/2010, 15h56   #1
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Par défaut Création d'un Thread

Bonjour à tous!

J'essaie actuellement d'encapsuler un traitement (calcul de balance comptable) assez long dans mon appli. La création d'un thread me paraît indiquée dans ce cas et j'ai donc mis en place les déclarations et la fonction AddrOf(fonction) dans mon code.
A la compil, pas de problème. L'appel de la fonction se fait correctement, mais il me semble avoir un problème avec la fonction "GetCurrentVbaProject(hProject)" (appelée depuis la fonction AddrOf): à sa sortie la variable hProject a toujours la valeur 0 et le traitement ne se poursuit pas, bien sûr.
J'avoue que j'utilise ce code "copié-collé" depuis la FAQ sans le comprendre entièrement, mais pour ce que j'en sais, il pourrait résoudre mon problème.
Je soupçonne que le problème se trouve dans l'appel de la fonction reproduit ci-après:
Code :
1
2
3
4
5
6
Sub CalculBalance411Solid()
          hThread = CreateThread(0&, 0&, AddrOf("CalculBalance411Solid"), 0&, 0&, hThreadID)
          CloseHandle hThread
          Dim e As Long
          e = TerminateThread(hThread, 0)
End Sub
J'ai passé ces paramètres sans en comprendre le sens .
En l'attente de vos conseils éclairés, merci d'avance.
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/11/2010, 16h25   #2
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Bonjour,
si je comprends ton code, tu crées un thread pour ta procédure de création de thread ?? Il est peut-être heureux que ton code n'a pas fonctionné.

La fonction AddrOf n'est-elle pas censée être l'équivalent Access97 de l'instruction VBA AddressOf des versions suivantes renvoyant l'adresse d'une fonction (pour les procédures je ne suis pas sûr) publique.
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/11/2010, 17h03   #3
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
En fait je crée un thread qui appelle un "sub" qui lui même calcule enregistrement par enregistrement, le solde (débit-crédit) d'une table 401-fournisseurs.
J'ai effectivement trouvé le post suivant:
http://www.developpez.net/forums/d56...sation-thread/
et modifié mon code en conséquence sans plus de succès.
(viré les références à vba332.dll) et remplacé l'appel de AdrOf par AddressOf).
Pour répondre à ta question: j'avais une procédure appelée "CalculBalance411Solid" dont j'ai coupé-collé le code dans "CalculBalance411SolidThread": j'appelle cette dernière comme suit:
Code :
1
2
3
4
5
6
Sub CalculBalance411Solid()
          hThread = CreateThread(ByVal 0&, ByVal 0&, AddressOf CalculBalance411Solid_Thread, ByVal 0&, ByVal 0&, hThreadID)
          CloseHandle hThread
          Dim e As Long
          e = TerminateThread(hThread, 0)
End Sub
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Sub CalculBalance411Solid_Thread()
          Dim mabd As Database, MonRec As Recordset, StrSQL As String, Balance As Currency, LaDate, Crit As String, WithBall As String, rep
 
 
          Set mabd = CurrentDb()
          StrSQL = "SELECT CCCpt, CCDeb, CCCre, CCBalSolid, CCDat FROM CPTE_CAISSE_Cli ORDER BY CCDat;"
          Set MonRec = mabd.OpenRecordset(StrSQL)
          DoCmd.Echo True, "Mise à jour de la balance compte clients, veuillez patienter..."
          DoCmd.OpenForm "PgBar"
          Forms!PgBar!PTxt = "Mise à jour de la balance globale..."
          DoEvents
 
          Do While MonRec.EOF = False
                    MonRec.Edit
                    Forms!PgBar!PgBar = MonRec.PercentPosition
                    Forms!PgBar!Pct = MonRec.PercentPosition / 100
                    Forms!PgBar.Repaint
                    DoEvents
                    LaDate = MonRec!CCDat
 
                    Balance = Nz(DSum("CCCre", "CPTE_CAISSE_Cli", "CCDat<=#" & Format(LaDate, "mm/dd/yyyy hh:nn:ss") & "#"), 0) - Nz(DSum("CCDeb", "CPTE_CAISSE_Cli", "CCDat<=#" & Format(LaDate, "mm/dd/yyyy hh:nn:ss") & "#"), 0)
 
                    MonRec!CCBalSolid = Balance
                    MonRec.Update
                    'DoEvents
                    MonRec.MoveNext
          Loop
          MonRec.Close
          DoCmd.Close acForm, "PgBar"
          DoCmd.Echo True, ""
End Sub
Voilà où j'en suis de mes réflexions pour l'instant et merci Ilank de ton attention (pour l'appel récursif c'était une erreur de frappe...)
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/11/2010, 17h45   #4
Membre éprouvé
 
Avatar de Tonioyo
 
Anthony Schricke
Développeur informatique
Inscription : juin 2008
Messages : 342
Détails du profil
Informations personnelles :
Nom : Anthony Schricke
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : juin 2008
Messages : 342
Points : 455
Points : 455
Bonsoir,

Si je me rappelle de ce que j'avais fait fait sur les thread, il y a fort longtemps, une fois le thread créé il est nécessaire de le lancer.

Attention aussi à ce que le code appellant reste chargé en mémoire durant l'éxection du thread sinon on obtiens un thread orphelin et là ... bonjour l'état de la mémoire.

Il faut savoir que les deux principaux systèmes d'exploitations ne possèdent pas de "garbage collector" pour nettoyer ces threads orphelins.

Il faut aussi s'assurer à la désallocation du code parent de la bonne désallocation du thread en mémoire. Ce qui est très probablement fait avec

Code :
e = TerminateThread(hThread, 0)

Un autre aspect très important en ce qui concerne les threads est le mécanisme de ressources. Un thread peu consommer / produire une / plusieurs ressources. La difficulté de la programmation par thread est de ne pas se trouver en conditions d'interblocage ce qui paralyserai l'ordinateur (et non pas simplement access) surtout à cause (de mémoire) de l'attente active sur la ressource.

Il faut aussi penser au mécanisme des interruptions pour pas que le thread s'arrête à l'instant t ou il ne devrait jamais s'arrêter. C'est surtout critique pour les systèmes embarqués.

Pour adressOf ce n'est qu'une instruction qui permet d'avoir l'adresse en mémoire du début d'un objet / d'une fonction.

Attention aussi au rôle des CallBack qui sont un mécanisme important des threads. Toujours de mémoire, ces méthodes sont les méthodes principale / de démarrage du thread. Elles sont analogues au main en C / C++ / Java et elle doivent très probablement respecter une signature particulière.

J'espère avoir été utile et avoir permis diriger la reflexion vers la solution pour votre problème.

Cordialement,
__________________
loi de LeBlanc : Plus tard signifie jamais. extrait de Coder proprement Auteur:Robert C. Martin
Tonioyo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 26/11/2010, 17h56   #5
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Ok, tu fais trop régulièrement appel au DoEvents dans ton code ce qui ralentit l'exécution du code.
Pour faire simple, ton formulaire n'a en fait besoin d'être rafraichi qu'après chaque 1% de tâche accomplie. Soit un test du genre :
Code :
1
2
3
4
5
If CurPercent >= OldPercent + 1 Then
 OldPercent=CurPercent
 form.Repaint
 DoEvents
End If
limite le nombre de DoEvents à 100.
Je ne crois pas qu'il soit suffisant de créer un thread pour qu'il s'exécute pour autant, à voir ?

Sinon, il y a ici une première ébauche de simulation de multithreads sans threads.
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 29/11/2010, 14h38   #6
Membre éprouvé
 
Avatar de Tonioyo
 
Anthony Schricke
Développeur informatique
Inscription : juin 2008
Messages : 342
Détails du profil
Informations personnelles :
Nom : Anthony Schricke
Localisation : France, Haute Garonne (Midi Pyrénées)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : juin 2008
Messages : 342
Points : 455
Points : 455
J'ai trouvé en première partie d'un article la définition d'un thread
http://alwin.developpez.com/tutorial/JavaThread/

Un thread doit être démarrer pour qu'il puisse fonctionner. A la création d'un thread, des arguments obligatoires et le plus important est celui de la routine.

La routine d'éxecution est une méthode qui serra executée tant que le thread serra en vie et actif. C'est à dire qu'il n'y a pas besoin d'écrire de boucle à l'intérieur du code de la routine.
Dans l'exemple du premier article cité il s'agit des CallBacks.
Donc par exemple, une routine qui aurait ce code :

Passe toute sa vie à incrémenter la variable i qui soit dit en passant doit être accessible donc déclarée au minimum static.

Pour la programmation de threads, la difficulté est de gérer les problèmes d'accès concurentiels aux ressources (par exemple la variable i). Ce qui dans le cas présent concerne tous les objets manipulés à l'intérieur de la routine.

Les objets manipulés sont des objets Access et la routine va s'éxecuter de manière totalement indépendante du contexte d'execution. Donc l'accès à des objets d'Access risquent fortement d'être compromis.

Le paramètre pour la routine est un pointeur sur fonction (j'ai donc de sérieux doutes concernant une Sub qui est une procedure).

D'où la méthode AddrOf de l'article, à éventuellement remplacer par AddressOf dans les versions d'Access plus récentes.

La méthode AddrOf calcule l'adresse mémoire de la première instruction à éxecuter d'une méthode passée en paramètre.

La mise en place d'un traitement lourd dans un thread n'est pas chose facile.
L'utilisation du thread ici serrai de prendre en charge uniquement le calcul mathématique des données à traiter.

Cordialement,
__________________
loi de LeBlanc : Plus tard signifie jamais. extrait de Coder proprement Auteur:Robert C. Martin
Tonioyo est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/11/2010, 09h07   #7
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Merci Ilank et Tonioyo de vos réponses,

Je vais essayer d'utiliser vos réponses dans mon appli. Même si le thread s'avère difficile à mettre en place dans ce contexte, j'ai réussi à diminuer le temps de traitement du calcul des balances de moitié .

Cela dit je m'enferre peut-être sur cette voie ??? Il existe peut-être une méthode simple pour effectuer ce genre de calculs.

En gros une colonne débit, une colonne crédit et une colonne balance:
basiquement, balance= somme(débit - crédit).

Ce qui plombe ce calcul c'est l'utilisation de fonctions de domaine au lieu de SQL.

Merci encore de votre intéret.
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/11/2010, 09h47   #8
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Bonjour,
je n'y connais pas grand chose en compta, pourquoi affectes-tu à chaque ligne la balance totale d'une date donnée.
De plus, la balance étant un champ calculé tu peux aisément t'en penser dans la table, il s'agît plus d'un champ supplémentaire dans une requête de présentation.

Code :
1
2
3
 SELECT A.CCpt, A.CCDeb, A.CCCre, A.CCDat, Balance
FROM CPTE_CAISSE_Cli as A INNER JOIN (SELECT Sum(CCDeb-CCCre) As Balance, CCDat,CCpt FROM CPTE_CAISSE_Cli GROUP BY CCpt,CCDat) As B ON B.CCDat=A.CCDat AND B.CCpt=A.CCpt
ORDER BY A.CCDat;
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 30/11/2010, 12h05   #9
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Merci Ilank pour ta réponse rapide,

(En plus j'ai apris une syntaxe que je ne connaissais pas en posant un alias sur un nom de table -A - B).

Cela dit, une balance comptable permet d'avoir la position d'un compte à une date donnée (tenant compte, bien sûr de l'antériorité). ce qui, basiquement veut dire que si hier, mon solde chez tel ou tel tiers dans ma compta, était de :
hier (débit=20 - crédit=10)= balance = 10
aujourd'hui (débit=10 - crédit=15)= balance = 5 (et non -5)


Le top serait d'avoir une requête mise à jour qui me permettrait de calculer et mettre à jour la balance de toute la table en une seule opération SQL (rapide).

Merci encore
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 02/12/2010, 09h04   #10
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Bonjour,

d'accord la requête devrait plus ressembler à ceci :

Code sql :
1
2
3
4
SELECT A.CCpt, A.CCDeb, A.CCCre, A.CCDat, Sum(Nz(B.CCDeb,0)-Nz(B.CCCre,0)) AS Balance
FROM CPTE_CAISSE_Cli AS A LEFT JOIN CPTE_CAISSE_Cli AS B
 ON B.CCpt=A.CCpt AND B.CCDat<=A.CCDat
GROUP BY A.CCpt, A.CCDeb, A.CCCre, A.CCDat;
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/12/2010, 16h39   #11
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Bonjour ilank

Je me suis emballé un peu vite ce matin en considérant ta réponse comme valable.

Tout compte fait lorsque je regarde les valeurs renvoyées par ta requête j'ai quelque chose de la forme

Code :
1
2
3
4
5
6
7
8
9
 
Date          Débit     Crédit     Balance
01/01/10     5                        5
02/01/10                  10        -10
 
alors que je devrais avoir:
Date          Débit     Crédit     Balance
01/01/10     5                        5
02/01/10                  10         -5
Pourtant je sens qu'avec le critère sur le LEFT JOIN, je touche au but
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/12/2010, 17h21   #12
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Je continue de chercher une solution "pure SQL": peux-tu me commenter ton:

dans le "LEFT JOIN" du "FROM" ?

le QBE ne pouvant pas représenter ce type de requêtes, je me trouve un peu désarmé pour le bidouiller...
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/12/2010, 18h15   #13
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Bonsoir,
Code sql :
B.CCpt=A.CCpt AND B.CCDat<=A.CCDat
indique que pour chaque ligne de transaction pour un compte on recherche les valeurs des dates précédentes ou identiques de la date de ligne pour ce compte.
C'est sûrement le critère qui pose problème puisqu'il limite la balance par compte.
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 06/12/2010, 20h03   #14
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Bonsoir,

Le champ CCpt est un auto-incrément, clé unique de cette table , je ne pense pas qu'il puisse poser un problème dans le LEFT JOIN dans ce cas. Ou alors quelque chose m'échappe?

Pour moi ce qui semble ne pas s'effectuer comme opération c'est le critère de la jointure:

et d'ailleurs ce qui s'affiche dans le champ "Balance" est issu du Débit-Crédit de la même ligne, sans tenir compte des dates antérieures.
Pour info j'y ai passé l'après-midi en essayant plusieurs variantes dont la création de requêtes temporaires "A" et "B" sur lesquelles porte ton bout de code, sans plus de résultat...
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/12/2010, 09h38   #15
Membre Expert
 
Inscription : avril 2006
Messages : 1 050
Détails du profil
Informations forums :
Inscription : avril 2006
Messages : 1 050
Points : 1 230
Points : 1 230
Bonjour,
si le champ CCpt est unique dans la table, le critère de jointure
Code sql :
B.CCpt=A.CCpt AND B.CCDat<=A.CCDat
n'a aucun sens; une même ligne ne peut avoir plusieurs dates.

La requête doit être :
Code sql :
1
2
3
SELECT A.CCpt, A.CCDeb, A.CCCre, A.CCDat, SUM(Nz(B.CCDeb,0)-Nz(B.CCCre,0)) AS Balance 
FROM  ... AS A LEFT JOIN ... AS B ON B.CCDat<=A.CCDat
GROUP BY A.CCpt, A.CCDeb, A.CCCre, A.CCDat;
ilank est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 07/12/2010, 10h55   #16
Membre actif
 
Avatar de Ric500
 
Homme Richard
Ingénieur développement logiciels
Inscription : août 2004
Messages : 166
Détails du profil
Informations personnelles :
Nom : Homme Richard
Localisation : France

Informations professionnelles :
Activité : Ingénieur développement logiciels
Secteur : Tourisme - Loisirs

Informations forums :
Inscription : août 2004
Messages : 166
Points : 157
Points : 157
Effectivement,

J'ai modifié en ce sens la requête ce matin dès mon arrivée au bureau. Cà a l'air de fonctionner car la requête se lance sans tousser, par contre j'ai dû l'interrompre car le temps de traitement est encore plus long que par code (sur une table qui pour l'instant ne comporte que 5300 lignes).
Ric500 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse Proposer ce sujet en actualité
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 21h11.


 
 
 
 
Partenaires

Hébergement Web