Domanda

Chiedo scusa in anticipo; questa è una lunga domanda Ho cercato di semplificare il più possibile ma è ancora un po 'più prolisso di quanto mi piacerebbe vedere.

In alcuni codici legacy, abbiamo una raccolta VB6. Questa raccolta aggiunge oggetti tramite il metodo .Add e li rimuove tramite il metodo .Remove. Tuttavia, tramite la traccia posso vedere che a volte quando viene chiamato .Remove sembra che la classe termina per l'oggetto non viene chiamato. Ma non è coerente; succede solo di rado e non riesco a isolare le circostanze in cui non riesce a licenziare la classe termina.

Considera il seguente codice dimostrativo:

Option Explicit
Private Const maxServants As Integer = 15
Private Const className As String = "Master"
Private Sub Class_Initialize()
    Debug.Print className & " class constructor "
    Set g_coll1 = New Collection
    Dim i As Integer
    For i = 1 To maxServants
        Dim m_servant As Servant
        Set m_servant = New Servant
        m_servant.InstanceNo = i
        g_coll1.Add Item:=m_servant, Key:=CStr(i)
        Debug.Print "Adding servant " & m_servant.InstanceNo
    Next
End Sub
Private Sub Class_Terminate()
    Dim i As Integer

    For i = maxServants To 1 Step -1
        g_coll1.Remove (CStr(i))
    Next

    Debug.Print className & " class terminator "
    Set g_coll1 = Nothing
    Exit Sub

End Sub

e

Option Explicit
Private Const className As String = "Servant"
Private m_instanceNo As Integer
Private Sub Class_Initialize()
    m_instanceNo = 0
    Debug.Print className & " class constructor "
End Sub
Public Property Get InstanceNo() As Integer
    InstanceNo = m_instanceNo
End Property
Public Property Let InstanceNo(newInstanceNo As Integer)
    m_instanceNo = newInstanceNo
End Property
Private Sub Class_Terminate()
    Debug.Print className & " class terminator for " & CStr(Me.InstanceNo)
End Sub

e questo è il codice del cablaggio di prova:

Option Explicit
Global g_coll1 As Collection
Public Sub Main()
    Dim a As Master
    Set a = New Master
End Sub

Ora, per ogni esecuzione, viene sempre invocato il class_terminate di Servant. E non riesco a vedere nulla nel codice di produzione che dovrebbe mantenere l'oggetto nella raccolta a cui viene fatto riferimento.

1.) Esiste un modo per forzare la chiusura della classe sul Rimuovi? Cioè, posso chiamare Obj.Class_Terminate ed essere certo che funzionerà ogni volta?

2.) Sul mio codice di produzione (e sulla mia piccola app di test) le classi sono contrassegnate come "Instancing - 5 MultiUse". Mi rendo conto che questo potrebbe essere una sorta di problema di threading; esiste un modo efficace per dimostrare (o confutare) che il multi-threading è la causa di questo problema: una sorta di traccia che potrei aggiungere o qualche altro tipo di test che potrei eseguire?


MODIFICA: Per il commento perspicace di MarkJ qui sotto, dovrei aggiungere che il test pubblicato sopra e il codice di produzione sono entrambi exe ActiveX - parte del motivo per cui chiedo del mulit-threading.

È stato utile?

Soluzione

Abbiamo riscontrato un problema simile, ma in cui è stato possibile rintracciare la non terminazione degli oggetti fino a un'istanza che si trova altrove nella nostra applicazione.

Alla fine, abbiamo dovuto scrivere il nostro metodo di Termination in questo modo:

Private Sub Class_Terminate()
    Terminate
End Sub

Public Sub Terminate()
    'Do real termination in here'
End Sub

Quindi ogni volta che vuoi veramente che la classe venga chiusa (cioè quando chiami g_coll1.Remove), puoi anche chiamare Terminate sull'oggetto trattenuto.

Penso che potresti anche rendere pubblico Class_Terminate, ma secondo me è un po 'brutto.

Riguardo al tuo punto (2), penso che sia molto improbabile che si tratti di un problema di threading, ma non riesco a pensare a una buona prova / test dalla cima della mia testa. Suppongo che una cosa molto seria che puoi considerare sia: usi manualmente il threading nella tua applicazione? VB6 non esegue molti thread automaticamente ... (vedi modifica sotto)

[ Modifica ] MarkJ ci dice che apparentemente costruire come un'applicazione ActiveX significa che VB6 lo fa esegue automaticamente il threading. Qualcun altro dovrà esplorare le implicazioni di questo, dal momento che non ne avevo familiarità!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top