Visual Basic - использование вложенных Mutex в многопоточных приложениях - риски и предложения - PullRequest
2 голосов
/ 17 ноября 2010

Добрый вечер, коллеги-укладчики, у меня мьютекс и связанный вопрос о

// ¦ = Run one or the other per call to routine

|GROUP A|   GROUP B  |
| A & B GROUP MUTEX  |
|=======|============|
|A1 & A2¦ B1 & |B2|B3|
               |MUTEX|
               |==|==|
               |B2¦B3|

Ситуация

Является ли эта ситуация безопасной или жизнеспособной?

У меня есть 5 сабовподпрограммы в VB.NET, и я могу запускать их в 2 группах, состоящих из отдельных подмножеств асинхронным потоком.

Однако, как показывает ужасно грубый текстовый график, работа мьютекса над подмножеством B

Логика

Группе A и B приходится ждать друг друга, если задания были запущены либо - A & B GROUP MUTEX помогает держать это под контролем.

ВнутриГруппа A может выполнять обе процедуры одновременно (B придется ждать завершения A1 и A2).

Группа B, в которой B1, B2 и B3 могут запускать B1 одновременно с любой из них.B2 и B3, но B2 и B3 не могут работать одновременно , поэтому проверка подмножества MUTEX.

Обновление: @pstrjds хорошо подошла к вопросу с помощью синхронизации вместо:причина, по которой я использую Mutex, а не блокировку синхронизациик тому, что мне нужно сделать этот процесс многопользовательским безопасным, так как в подпрограммах много SQL и операций на основе данных, которые требовали блокировки программы, в то время как несколько SQL-транзакций выполняются в разных базах данных на 3 разных серверах, чтобыобновляйте их одновременно и безопасно - обработка транзакций в SQL выполнена и работает хорошо, отсюда и разбитый псевдо-код.@pstrjds правильно говорит, что это использует потоки, порожденные одним классом, однако в подпрограммах он вызывает веб-службу (часть работы группы B в B2 и B3), которая обновляет отдельный сторонний сервер.</Wall-o-Text>

Псевдо-код

К сожалению, точный код довольно длинный, но я использую эту структуру:

Sub AGroup_Method()

    Dim bln_FirstInstance As Boolean

    Using objABMutex As New Mutex(True, "Global\AB_MutexLock", blnFirstInstance)
        If bln_FirstInstance Then
            //Start Threads for subroutine A1 And then A2
            StartThread_A1()
            StartThread_A2()
        Else
           //Post that Group A subroutine needs to wait for Group B
        End If
    End Using
End Sub

Sub BGroup_Method(Byval p_blnRunBTwo as Boolean)

    Dim bln_FirstInstance As Boolean
    Dim blnBGroup_FirstInstance As Boolean

    Using objABMutex As New Mutex(True, "Global\AB_MutexLock", bln_FirstInstance)
        If bln_FirstInstance Then
            //Do subroutine group B

            //Start B1
            StartThread_B1()

            Using objBGroupMutex As New Mutex(True, "Global\BGroup_MutexLock", blnBGroup_FirstInstance)
                If p_blnRunBTwo 
                    If blnBGroup_FirstInstance Then
                        //Wait for mutex from B3 and then run B2
                        StartThread_B2
                    End If
                Else 
                    If blnBGroup_FirstInstance Then
                        StartThread_B3
                    End If
                End If   
            End Using                     
        Else
           //Post that Group B subroutine needs to wait for Group A

        End If

    End Using

End Sub

Справка!

ЧтоЯ хотел бы спросить, является ли вложение мьютекса возможной проблемой, если это плохая практика и что есть лучший способ реализовать это, используя многопоточную систему.

Ответы [ 2 ]

1 голос
/ 17 ноября 2010

Да, это плохая практика.Я отсканировал вопрос несколько раз, но я не чувствую себя достаточно хорошо информированным, чтобы дать хороший ответ.Это проблема, если вы не можете легко объяснить свою модель блокировки, и у вас возникают проблемы с получением хорошей картинки, которая проясняет ситуацию, тогда также становится очень трудно рассуждать о количестве возможных перестановок состояний.

Невозможность рассуждать обо всех возможных перестановках состояний может привести к очень неприятным штрафам за время выполнения.Тупик.

1 голос
/ 17 ноября 2010

Я не думаю, что вы не используете Mutex здесь, но если весь код находится в одном классе, и вы просто создаете рабочие потоки в этом классе (я основываю это на псевдокоде, который выпредставлены) вы можете обойтись, просто объявив два объекта и используя SyncLock для обработки доступа.Это должно быть более производительным, чем использование Mutex (опять-таки при условии, что весь этот код находится в одном классе, а потоки запускаются из класса и вам не требуется межпроцессная сериализация)

Dim abLock as Object = new Object()
Dim bLock as Object = new Object()

Sub AMethod()
    SyncLock abLock
    ' Do stuff here
    End SyncLock
End Sub

Sub BMethod(ByVal pInBTwo As Boolean)
    SyncLock abLock
        StartB1Thread()

        SyncLock bLock
            ' Do B2 or B3 stuff
        End SyncLock
    End SyncLock
End Sub

Изменить: Добавлена ​​информация об именованном мьютексе в соответствии с предложением: Если вы используете мьютекс с глобальным именем, вы можете столкнуться с проблемами с разрешениями, если пользователь, выполняющий код, имеет ограниченный доступ (например, запуск в качестве гостя).Другая проблема, которая вступает в игру, - это создание с правильным MutexAccessRule, чтобы другой пользователь мог получить к нему доступ после его создания.Пример кода на C #:

Mutex mutex = null;
bool exists = true;

// Using try catch since as far as I know there is no other way to check if
// a mutex exists, but to open it and catch the exception, this may be changed
// in .Net 4.0, I originally wrote this targeting 2.0
try
{
     mutex = Mutex.OpenExists(@"Global\MyMutexName");
}
catch
{
     exists = false;
}

if (!exists)
{
     SecurityIdentifer sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
     MutexAccessRule rule = new MutexAccessRule(sid, MutexRights.FullControl,
         AccessControlType.Allow);
     MutexSecurity security = new MutexSecurity();
     security.AddAccessRule(rule);

     bool createdNew = false;
     mutex = new Mutex(false, @"Global\MyMutexName", out createdNew, security);
}

Приведенный выше код создаст мьютекс, который не ограничен пользователем, который его создал, это важно, если вы находитесь в среде служб терминалов, где несколько человек работают с одной и той же программойв то же время.Вы можете быть в порядке, ограничивая некоторые из разрешений больше, чем я сделал там (на самом деле я создаю его почти без ограничений), но без этого вы можете сделать так, чтобы человек A создавал мьютекс, а человек B создавал исключение, потому что они не могли получить доступ к мьютексу.созданный человеком А.

...