Událost z jiného vlákna   zodpovězená otázka

VB.NET, Threading, C++/C

Dobrý den,

Na mob. zařízení s CE6.5 bych potřeboval sledovat velikost obsazení paměti.

Napsal jsem si tuto třídu, ve které je vlastní vlákno vykonávající nekonečnou smyčku a v každém průchodu se zjistí procentuální vytížení paměti. Pokud se bude číslo lišit od předchozího výsledku zavolá se událost MemoryUsageChanged s parametrem v as int32.

V hlavním vlákně na formu se mi vyvolá tato událost, avšak nevím jak z ní správně přistupovat k prvku na formu.

Nyní mám funkční řešení ale nevím zdali je správně.

Vlákno se spouští procedurou Start() z formLoad události.

Formulář s prvkem

    Private WithEvents ramLoader As New clsMemoryUsage
    Private Delegate Sub SetProgressBar()
    Private value As Int32
    Private Sub ramLoader_MemoryLoadChanged(ByVal sender As Object, ByVal v As Integer) Handles ramLoader.MemoryLoadChanged

        If Me.ProgressBar1.InvokeRequired Then
            Me.value = v
            Me.ProgressBar1.BeginInvoke(New SetProgressBar(AddressOf Me.ZmenaProgressBaru))
        Else
            Me.value = v
            Me.ZmenaProgressBaru()
        End If
    End Sub
    Private Sub ZmenaProgressBaru()
        Me.ProgressBar1.Value = Me.value
    End Sub

Třída s druhým vláknem.

Public Class clsMemoryUsage

    Private _lastLoad As Int32
    Private _start As Boolean
    Public Delegate Sub MemoryChangedDelegate(ByVal sebder As Object, ByVal e As Int32)
    Public Event MemoryUsageChanged As MemoryChangedDelegate
    Private _isStarted As Boolean = False
    Private _th As New Thread(AddressOf Me.NonEndCycle)

    ''' <summary>
    ''' Cyklus pro druhé vlákno
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub NonEndCycle()
        While True
            Me.Load = Me.GetUsageMemory
            Thread.Sleep(5000)
        End While
    End Sub

    ''' <summary>
    ''' Procentuální vytížení paměti
    ''' </summary>
    Public Property Load() As Int32
        Get
            Return Me._lastLoad
        End Get
        Set(ByVal value As Int32)
            If value <> Me._lastLoad AndAlso value >= 0 AndAlso value <= 100 Then
                Me._lastLoad = value
                RaiseEvent MemoryUsageChanged(Me, value)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Spuštění druhého vlákna
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub Start()
        If Me._isStarted Then Exit Sub
        Me._th.Start()
        Me._isStarted = True
    End Sub

    ''' <summary>
    ''' Pinvoke funkce pro status paměti
    ''' </summary>
    <DllImport("coredll.dll")> _
    Private Shared Function GlobalMemoryStatus(ByRef ms As MEMORYSTATUS) As Int32
    End Function
    ''' <summary>
    ''' Struktura pro pinvoke funkci
    ''' </summary>
    ''' <remarks></remarks>
    Public Structure MEMORYSTATUS
       ...
    End Structure
    ''' <summary>
    ''' Vrátí procentuální vytížení paměti
    ''' </summary>
    Public Function GetUsageMemory() As Int32
        Dim ms As New MEMORYSTATUS
        ms.dwLenght = Marshal.SizeOf(ms)
        GlobalMemoryStatus(ms)
        Return ms.dwMemoryLoad
    End Function
End Class
nahlásit spamnahlásit spam 0 odpovědětodpovědět

Řešíte to zbytečně složitě. Použijte klasický System.Windows.Forms.Timer, který také používá vlastní vlákno a který má již synchronizaci zabudovanou v sobě.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

To ano máte pravdu, v tomto případě by to bylo nejlepší.

Já bych, ale potřeboval vysvětlit jak dostat průběžný výsledek vedlejšího vlákna do hlavního. Např. jak událost Timeru.Tick přistupuje k hlavnímu vláknu, když timer nebo jeho část běží v jiném vlákně. Chtěl bych pochopit princip "synchrinizace".

Nedaří se mi najít vhodný (srozumitelný) článek.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

V "bežnom" .nete sa to robí funkciou Invoke na objekte formulára, v ktorého ui vlákne chcete funkcii predaný delegát zavolať.

Public Class Form1
    'Zmena stavu
    Public Sub StateChanged(ByVal state As Integer)
        TextBox1.Text = state.ToString()
    End Sub
    'Druhé vlákno
    Public Sub Thread2()
        For x As Integer = 0 To 5000
            Me.Invoke(New Action(Of Integer)(AddressOf StateChanged), x)
            Threading.Thread.Sleep(50)
        Next
    End Sub
    'Objekt vlákna
    Dim thr As Threading.Thread
    'Ukončiť vlákno pri zatvorení formu
    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        thr.Abort()
    End Sub
    'Spustenie vlákna
    Public Sub FormLoad(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        thr = New Threading.Thread(New Threading.ThreadStart(AddressOf Thread2))
        thr.Start()
    End Sub
End Class

Funkčné po pridaní jedného TextBoxu(ponechať pôvodné meno).

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Tak synchronizace vláken je nutná hlavně u ovládacích prvků ve Windows Forms. Hlavní myšlenka je toto: Dvě nebo více na sobě nezávislých vláken nemohou zároveň nastavovat stejnou proměnnou (libovolnou vlastnost ovládacího prvku), protože by mohlo a velmi pravděpodobně došlo ke kolizi. Synchronizací tedy zajistíte, že vlákno B může přistupovat k proměnné až v okamžiku, kdy skončí vlákno A. Synchronizace se dá provádět několika způsoby, kde ten první je použití metody Invoke a delegáta metody, kterou chcete spustit v tom správném vlákně a druhý způsob je použití třídy WindowsFormsSynchronizationContext, který se hodí pro použití ve vlastní třídě.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji za odpovědi,

Windows.Forms.SynchronizationContext nastuduji.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback