Форум программистов, компьютерный форум, киберфорум
Visual Basic .NET
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.53/15: Рейтинг темы: голосов - 15, средняя оценка - 4.53
0 / 0 / 0
Регистрация: 21.03.2017
Сообщений: 24
1

Вызов события в MemoryMappedFiles

10.09.2018, 17:09. Показов 2795. Ответов 21

Author24 — интернет-сервис помощи студентам
Приветствую!
Столкнулся с одной проблемой. Создал обмен данными с помощью отражения. Вопрос интересует такой, можно создать событие таким образом, чтобы Приложение 2 при каждом новом полученном сообщении автоматически активировал событие и добавлял сообщение в TEXT_BOX? Примерно как с сокетами.
Очень буду благодарен за ответ!

Приложение 1
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Dim sharedMemory As MemoryMappedFile
 
Protected Overrides Sub OnStart(ByVal args() As String)
sharedMemory = MemoryMappedFile.CreateOrOpen("Global\MemoryFile", 1000 * 2 + 4)
End Sub
 
Public Sub MAPFILE(ByVal msg As String)
        Dim message As Char() = msg
        Dim size As Integer = message.Length
        Using writer As System.IO.MemoryMappedFiles.MemoryMappedViewAccessor = sharedMemory.CreateViewAccessor(0, size * 2 + 4, MemoryMappedFileAccess.Write)
            writer.Write(0, size)
            writer.WriteArray(Of Char)(4, message, 0, message.Length)
        End Using
    End Sub
Приложение 2
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Dim size1 As Integer
Dim sharedMemory As MemoryMappedFile
    Private Sub MAPS(ByVal message As Char())
        Try
            Using reader As MemoryMappedViewAccessor = sharedMemory.CreateViewAccessor(0, 4, MemoryMappedFileAccess.Read)
                size1 = reader.ReadInt32(0)
            End Using
            Using reader = sharedMemory.CreateViewAccessor(4, size1 * 2, MemoryMappedFileAccess.Read)
                message = New Char(size1 - 1) {}
                reader.ReadArray(Of Char)(0, message, 0, size1)
            End Using
            TEXT_BOX(message & vbCrLf)
        Catch ex As Exception
            TEXT_BOX("NO MAP FILE EXIST" & vbCrLf)
        End Try
    End Sub
 
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        sharedMemory = MemoryMappedFile.OpenExisting("Global\MemoryFile", size1 * 2 + 4)
        Dim SENDERS As New System.Threading.Thread(AddressOf MAPS)
        SENDERS.Start()
End Sub
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.09.2018, 17:09
Ответы с готовыми решениями:

Нестабильная работа MemoryMappedFiles
Друзья, приветствую всех! :) Подскажите, пожалуйста, в чём может быть причина нестабильной...

Вызов события Click usercontrol
Добрый день! Создал свой собственный UserControl, который внутри себя содержит несколько...

Вызов VB.Net диалога из события Word
В моём приложении из VB.Net загружаются документы Word. Необходимо осуществить открытие диалогового...

Вызов события из потока: ошибка доступа к элементу управления
Смысл задачи следующий: В отдельном потоке в цикле проверяется пинг до удаленного хоста в...

21
1047 / 898 / 211
Регистрация: 29.09.2015
Сообщений: 1,004
12.09.2018, 23:07 2
Создайте таймер, который будет периодически проверять данные, а при наличии изменений вызывать дальнейшее действие или событие
1
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
06.11.2018, 12:15 3
Цитата Сообщение от Sklifosofsky Посмотреть сообщение
Создайте таймер, который будет периодически проверять данные
Не надо так делать.

Лучше создайте системный объект‐событие EventWaitHandle с общим именем для всех процессов. После записи данных в файл устанавливайте событие в сигнальное состояние методом Set. Ожидающие данных в файле потоки ждут этого сигнала через WaitOne().
2
395 / 314 / 53
Регистрация: 14.08.2014
Сообщений: 1,010
06.11.2018, 16:57 4
Замабувараев, а как вся эта штука в сборе работает?
Может пример есть простецкий?

Я как-то давно пробовал разобраться, так и не понял толком принцип работы. Сейчас точно не помню, но по-моему исключения какие-то вылетали, что нет доступа.
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
06.11.2018, 21:31 5
Цитата Сообщение от Дядя Корней Посмотреть сообщение
а как вся эта штука в сборе работает?
VB.NET
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
Пример когда поток ждёт наступления объекта‐события. Поток может находиться даже в другом процессе.
Имя объекта‐события должно быть уникальным.
Sub Main()
    Dim weh = New Threading.EventWaitHandle(False, Threading.EventResetMode.AutoReset, "Событие")
 
    Dim hThread = New Threading.Thread(AddressOf ThreadProc)
    hThread.Start()
 
    Do
        ' Что‐то сделать, например, записать в файл, в данном примере просто ждём ввода с консоли
        Console.ReadLine()
 
        ' Установить событие, сигнализировав ожидающим потокам, что всё готово
        weh.Set()
    Loop
End Sub
 
Sub ThreadProc()
    ' Создать или открыть событие
    Dim weh = New Threading.EventWaitHandle(False, Threading.EventResetMode.AutoReset, "Событие")
 
    Do
        ' Ожидать, когда кто‐то установит событие
        weh.WaitOne()
 
        ' После установки события можно делать полезную работу, в данном примере просто выводим надпись на консоль
        Console.WriteLine("Событие случилось")
    Loop
 
End Sub
3
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
08.08.2019, 15:54 6
Замабувараев, спасибо за пример.
Но вот какая проблема. Если потоков больше двух, то сигнал принимает только один поток. Можно ли заставить таким образом оповещать более 2х потоков?

Добавлено через 6 минут
И да, еще добавлю, чтобы поток завершался вместе с приложением, устанавливать
VB.NET
1
.IsBackground = True
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
09.08.2019, 12:52 7
Сам задал вопрос, сам же и отвечу.
Убираем AutoReset
VB.NET
1
eventX = New Threading.EventWaitHandle(False, Threading.EventResetMode.ManualReset, "000" & myName)
При установке сигнала используем флаг. А в цикле его проверяем и сбрасываем
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
Sub WaitSignal()
        Do
            eventX.WaitOne()
            If wasSendEvent Then
                wasSendEvent = False
                eventX.Reset()
                GoTo ItWasMyEvent
            End If
            'Выполняем необходимые действия
ItWasMyEvent:
        Loop
    End Sub
1
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
12.08.2019, 15:23 8
Цитата Сообщение от rvs_dk Посмотреть сообщение
GoTo ItWasMyEvent
Вместо этого оператора Goto рекомендую использовать Continue Do.
1
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
12.08.2019, 15:36 9
Да спасибо, книг никаких нет, а методом подбора подходящего Intellisence мне этого не предложил.
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
18.08.2019, 17:42 10
Вот здесь есть спецификация по VB.NET https://github.com/dotnet/vblang
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
10.09.2019, 14:25 11
Замабувараев, подскажите пожалуйста.
Вот у меня работают несколько потоков, которые слушают друг друга как описано выше.
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
        Try
            Do
                eventX.WaitOne()
                If wasSendEvent Then
                    wasSendEvent = False
                    eventX.Reset()
                    Continue Do
                End If
                'Выполняем необходимые действия
                DoWork()
            Loop
        Catch ex As ThreadInterruptedException
 
        End Try
Тот поток, который послал сообщение - он и сбрасывает eventX.Reset(). Но, как оказалось, что второй/третий поток может не дождаться eventX.WaitOne(), т.к. пославший сообщение поток получит его раньше и сбросит.
Есть ли простой выход из данного затруднения? или придется городить учет всех потоков и дожидаться ответа от каждого.
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
13.09.2019, 08:28 12
Как вариант, есть метод WaitAll. Он должен принимать массив всех waitHandles. Но как я могу получить этот массив, если у меня они в разных процессах?
Коллеги, есть мысли у кого-то?
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
16.09.2019, 18:29 13
Я уже говорил, что необходимо создать событие EventWaitHandle с именем.

https://docs.microsoft.com/en-... em_String_

Затем и обращаться по этому имени из разных процессов.

Добавлено через 2 минуты
Цитата Сообщение от rvs_dk Посмотреть сообщение
Но, как оказалось, что второй/третий поток может не дождаться eventX.WaitOne(), т.к. пославший сообщение поток получит его раньше и сбросит
Здесь необходимо передать EventResetMode.ManualReset
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
17.09.2019, 07:41 14
Замабувараев, я и передаю ManualReset и только пославший поток и сбрасывает сигнальное состояние
VB.NET
1
2
3
4
5
                If wasSendEvent Then
                    wasSendEvent = False
                    eventX.Reset()
                    Continue Do
                End If
Но проблема в том, что я сначала подумал, что все потоки получают сигнал, а потом по кругу опять, пока кто-то не сбросит eventX.Reset(). Логично, что это должен делать пославший поток. Но на практике может получиться, что сразу же установивший сигнал поток его и сбросит, так как ему первому выпадет.
Моя задача - организовать гарантированное получение сигнала всеми потоками.
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
17.09.2019, 09:04 15
Цитата Сообщение от rvs_dk Посмотреть сообщение
Но на практике может получиться, что сразу же установивший сигнал поток его и сбросит, так как ему первому выпадет.
Не понял, у вас там поток, который возводит событие, — он же это событие и ждёт, что ли?
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
17.09.2019, 12:21 16
Нет, у меня работают несколько потоков, которые слушают друг друга. И если один из них отправляет данные в MemoryMappedFile и сигнализирует об этом, то все без исключения потоки должны это прочитать. И когда все прочитают, сбрасывать сигнальное состояние.

Добавлено через 2 минуты
А по факту не получается так. Если предоставить право сбрасывать событие установившему потоку, то не факт, что все успеют его получить.

Добавлено через 59 минут
Цитата Сообщение от rvs_dk Посмотреть сообщение
Как вариант, есть метод WaitAll. Он должен принимать массив всех waitHandles. Но как я могу получить этот массив, если у меня они в разных процессах?
выше писал.
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
17.09.2019, 13:29 17
Цитата Сообщение от rvs_dk Посмотреть сообщение
Нет, у меня работают несколько потоков, которые слушают друг друга. И если один из них отправляет данные в MemoryMappedFile и сигнализирует об этом, то все без исключения потоки должны это прочитать.
Странная синтаксическая конструкция про потоков, которые слушают друг друга. Интуиция шепчет, что потоки должны ждать событие, а не друг друга. Наверное это просто фигура речи, а не логическая ошибка.

Вообще, я представляю себе код вот так.

Есть читающие потоки, которые ждут событие:
VB.NET
1
2
3
4
5
6
7
8
9
Sub ReadingThread()
    Do While Wait(hEvent)
        
        ' Событие взведено, теперь можно читать файл
        ReadFile(параметры)
        
        ' Файл прочитан, продолжаем ждать взведения события
    Loop
End Sub
И есть записывающий поток, который записывает данные в файл:
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sub WritingThread()
    Do
        ' Ждём данные, чтобы записать их в файл
        GetData(параметры)
 
        ' У нас есть данные для файла
        ' Сбрасываем событие
        Event.Reset()
        
        ' Записываем данные в файл
        WriteFile(параметры)
        
        ' Уведомляем читающие потоки, устанавливая событие
        Event.Set
    Loop
End Sub
А какая архитектура используется вами?

Добавлено через 15 минут
Цитата Сообщение от rvs_dk Посмотреть сообщение
Но как я могу получить этот массив, если у меня они в разных процессах?
Вы не читаете, что ли? Уже два раза же:
Цитата Сообщение от Замабувараев Посмотреть сообщение
создайте системный объект‐событие EventWaitHandle с общим именем для всех процессов
Цитата Сообщение от Замабувараев Посмотреть сообщение
Я уже говорил, что необходимо создать событие EventWaitHandle с именем.
Цитата Сообщение от Корпорация Микрософт
Именованные события

Операционная система Windows позволяет присваивать имена дескрипторам ожидания. Именованное событие применяется во всей системе. Это означает, что после создания именованное событие будет видимым для всех потоков во всех процессах. Таким образом, именованное событие можно использовать для синхронизации действий в разных процессах и потоках.
Вы можете создать объект EventWaitHandle, который представляет именованное системное событие, с помощью любого из конструкторов, использующих имя события.

Так как именованные события доступны во всей системе, может существовать несколько объектов EventWaitHandle, представляющих одно и то же именованное событие. При каждом вызове конструктора или метода OpenExisting создается новый объект EventWaitHandle. Если указать одно и то же имя несколько раз, создается несколько объектов, представляющих одно и то же именованное событие.
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
17.09.2019, 14:34 18
Цитата Сообщение от Замабувараев Посмотреть сообщение
фигура речи
да, именно так.

У меня все прекрасно работает. Проблема только в том, чтобы до всех потоков дошло событие, т. е. когда сбрасывать сигнальное состояние.
VB.NET
1
2
3
4
5
        Event.Reset()
        ' Записываем данные в файл
        WriteFile(параметры)
        ' Уведомляем читающие потоки, устанавливая событие
        Event.Set
Здесь все потоки будут получать сигнал постоянно. И потоки даже , как мне кажется не поймут что был Reset
Может мы друг друга не понимаем. Чуть позже выложу свой код.

Добавлено через 16 минут
VB.NET
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
Public Class eXPS
    Implements IConnectable
    'Implements IMovable
    Public X As Integer
    Public Y As Integer
    Public num As Integer
    Public myName As String
    Public pins As Integer
    Public loc As Integer = 1
 
    'Dim points() As Apoint
    Dim mFile As MemoryMappedFile
    Dim eventX As Threading.EventWaitHandle
    Dim eventThread As Threading.Thread
    Dim wasSendEvent As Boolean = False
    Dim Signals As New ArrayList
    Delegate Sub DoNext_()
    Private myDelegate As DoNext_ = New DoNext_(AddressOf DoNext)
 
    Dim m_Y As Integer
    Dim m_X As Integer
 
    'Structure Apoint
    '   Dim myCondition As Integer
    '   Dim Condition As Integer
    '   Dim pin As Integer
    'End Structure
 
    Public Sub New(rx As Integer, ry As Integer, n As Integer, aName As String, pinov As Integer, locat As Integer)
        ....
        myName = aName
        ....
 
        OnCreate()
    End Sub
 
    Sub OnCreate()
        mFile = MemoryMappedFile.CreateOrOpen(myName, 256)
        eventX = New EventWaitHandle(False, Threading.EventResetMode.ManualReset, "000" & myName)
        eventThread = New Thread(AddressOf WaitSignal) With {
            .IsBackground = True
        }
        eventThread.Start()
    End Sub
 
    Sub WaitSignal()
        Try
            Do
                eventX.WaitOne()
                If wasSendEvent Then
                    wasSendEvent = False
                    eventX.Reset()
                    Continue Do
                End If
                'Выполняем необходимые действия
                DoWork()
            Loop
        Catch ex As ThreadInterruptedException
 
        End Try
    End Sub
 
    Sub DoWork()
        Dim size1 As Integer
        Dim message As Char(), msg As String
        Try
            Using reader As MemoryMappedViewAccessor = mFile.CreateViewAccessor(0, 4, MemoryMappedFileAccess.Read)
                size1 = reader.ReadInt32(0)
            End Using
            Using reader = mFile.CreateViewAccessor(4, size1 * 2, MemoryMappedFileAccess.Read)
                message = New Char(size1 - 1) {}
                reader.ReadArray(Of Char)(0, message, 0, size1)
            End Using
            msg = New String(message)
            Signals.Add(msg)
            Me.Invoke(myDelegate)
        Catch ex As Exception
 
        End Try
    End Sub
 
    Public Sub Change(from As Integer, condition As Integer) Implements IConnectable.Change
 
        Dim msg As String = "A;" & (from - num).ToString & ";" & (condition + 50).ToString
        Dim message As Char() = msg
        Dim size As Integer = message.Length
 
        Using writer As System.IO.MemoryMappedFiles.MemoryMappedViewAccessor = mFile.CreateViewAccessor(0, 256, MemoryMappedFileAccess.Write)
            writer.Write(0, size)
            writer.WriteArray(Of Char)(4, message, 0, message.Length)
        End Using
        eventX.Set()
        wasSendEvent = True
    End Sub
    ......
End Class
0
COM‐пропагандист
859 / 768 / 147
Регистрация: 18.12.2014
Сообщений: 2,198
Записей в блоге: 4
17.09.2019, 17:38 19
Что сразу бросилось в глаза:
VB.NET
1
2
        eventX.Set()
        wasSendEvent = True
Здесь сначала устанавливается событие, а потом флаг. В этом случае ожидающий поток получит сигнал от события раньше, чем будет установлен флаг, и поток будет считать, что wasSendEvent = False. Возможно, это так и должно быть, но очень похоже на ошибку.

А здесь:
VB.NET
1
2
3
4
5
6
7
8
9
10
11
12
13
            Do
                eventX.WaitOne()
                
                If wasSendEvent Then
                    wasSendEvent = False
                    eventX.Reset()
                    Continue Do
                End If
                
                'Выполняем необходимые действия
                DoWork()
                
            Loop
Почему читающий поток сбрасывает событие? Неправильно. Сбрасывать событие должен делать тот, кто событие установил, то есть записывающий поток.

Читающий поток должен работать так:
VB.NET
1
2
3
4
5
6
7
            Do
                eventX.WaitOne()
                
                'Выполняем необходимые действия
                DoWork()
                
            Loop
0
129 / 108 / 24
Регистрация: 11.07.2017
Сообщений: 274
18.09.2019, 07:41 20
Ну тут логика так задумана. Каждый объект при создании запускает поток. И любой из объектов должен при изменении сообщить остальным, чтобы они также изменились. Поэтому каждый ждет сигнала от остальных. Когда сам меняется - передает другим, или просто должен измениться если другие попросили.

По факту сейчас имею - из 4х работающих объектов (потоков созданных объектом) могут все измениться при изменении одного, но чаще 1, 2 или ни одного вообще. Вот как раз это связано с тем, что сигнал не успевает ко всем попасть. кто-то его должен сбрасывать, вот пока и сделано, что сбрасывает пославший в надежде, что все уже его получили, но увы.

Как вариант, есть метод WaitAll. Он должен принимать массив всех waitHandles. Но как я могу получить этот массив, если у меня они обычно в разных процессах? Если бы в одной программе - я бы просто при создании объекта ее eventX добавлял бы в массив, а так придется наверное передавать его через MemoryMappedFile чтоле? И опять надо как то об этом сообщать остальным, либо еще один файл специально для этого создавать, в общем пока тупик.
0
18.09.2019, 07:41
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
18.09.2019, 07:41
Помогаю со студенческими работами здесь

Как запретить вызов события Click при нажатии правой кнопки мыши
Доброго времени суток. Как в своём UserControl запретить вызов события Click при нажатии правой...

Вызов события у объекта
Всем привет ) Подскажите пожалуйста как мне вызвать например событие у listbox.items...

Вызов события из другого события по нажатию клавиши
Всем привет! Есть кнопка на Windows.Forms, к ней привязано событие. Хочется, чтобы еще и по нажатию...

Вызов события из другого события
Есть событие button4_Click, надо из него вызвать button3_Click. Как сделать?


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru