Visual Basic - 在线程应用程序中使用嵌套互斥体 - 风险和建议

发布于 2024-10-03 03:12:55 字数 2491 浏览 0 评论 0原文

互斥锁和线程相关问题

// ¦ = 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|

晚上好,各位堆栈人员,我有一个关于情况的

这种情况安全或可行吗?

我在 VB.NET 中有 5 个子例程,我可以以异步线程方式将它们分为 2 个组(由单独的子集组成)来运行。

然而,正如上面极其粗糙的文本图所示,互斥锁也对子集 B 起作用。

如果作业已开始,逻辑

组 A 和 B 必须等待对方 - A & A 和 B。 B GROUP MUTEX 有助于控制这一点。

在 A 组内,两个例程可以同时开始(B 组必须等待 A1 和 A2 完成)。

B 组(包含 B1、B2 和 B3)可以与 B2 和 B3 同时运行 B1,但 B2 和 B3 不能同时运行,因此需要子集 MUTEX 检查。

更新: @pstrjds 在使用同步锁定方面提出了一个很好的观点:我使用互斥锁而不是同步锁的原因是因为我需要使这个过程多用户安全,因为子例程中有大量 SQL 和数据基于操作,需要锁定程序,同时在 3 个不同服务器上的不同数据库上执行多个 SQL 事务,以同时安全地更新它们 - SQL 中的事务处理已完成并且运行良好,因此分解了伪代码。 @pstrjds 正确地说,这是使用从一个类产生的线程,但是在子例程中,它调用一个 Web 服务(B 组在 B2 和 B3 中的工作的一部分),该服务更新单独的第 3 方服务器。

伪代码

不幸的是,确切的代码相当长,但我正在使用这个结构:

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

救命!

我想问的是互斥嵌套是否是一个可能的问题,是否是不好的做法等等,是否有更好的方法使用线程系统来实现这一点。

Good evening fellow stackers, I have a mutex and threaded related question about

// ¦ = 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|

Situation

Is this situation safe or viable?

I have 5 sub routines in VB.NET and I can run them in 2 groups comprising of seperate subsets in an asynchronous threaded manner.

However, as the horribly rough text-o-graph above shows, the mutex's work on the subset B as well.

Logic

Group A and B have to wait for the eachother if the jobs have started on either - A & B GROUP MUTEX helps keep this in check.

Inside Group A both can routines begin concurrently (B would have to wait for both A1 and A2 to be complete).

Group B, with B1, B2 and B3 can run B1 at the same time as either B2 and B3 but B2 and B3 cannot run concurrently, hence the subset MUTEX check.

Update:
@pstrjds made a good point with using Sync-locking instead: The reason I am using Mutex's and not Sync Lock is due to the fact that I need to make this process multi user safe as within the sub routines are a lot of SQL and data based operations which required the program to be locked whilst multiple SQL-Transactions are carried out on different databases across 3 different servers to update them concurrently and safely - transaction handling in SQL is done and working well hence the broken down psuedo-code.
@pstrjds is correct in saying that this is using threads spawned off the one class, however within the subroutines it calls to a web service (part of Group B's work in B2 and B3) which updates a separate 3rd party server.
</Wall-o-Text>

Psuedo-code

Unfortunately the exact code is rather long but I am using this structure:

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

Help!

What I would like to ask is if the mutex nesting is a possible problem, if it is bad practice whatnots and is there a better way of implementing this using a threaded system.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夏九 2024-10-10 03:12:55

我不认为你在这里使用互斥锁,但是如果所有代码都在同一个类中,并且你只是在该类中生成工作线程(我基于你提供的伪代码)你只需声明两个对象并使用 SyncLock 来处理访问即可。这应该比使用互斥体更具性能(再次假设所有这些代码都在同一个类中,并且线程是从该类启动的,并且您不需要进程间序列化)

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 抛出异常,因为他们无法访问互斥体由A人创建。

I don't think you are off the wall using a Mutex here, but if all of the code is in the same class and you are just spawning worker threads in that class (I am basing this off the pseudo-code you presented) you could get away with just declaring two objects and using SyncLock to handle the access. That should be more performative than using the Mutex (again assuming that all of this code is in the same class and the threads are launched from the class and you don't need inter-process serialization)

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

Edit: Added information about named mutex as per suggestion:
If you are using a globally named mutex you can run into permissions issues if the user running the code has limited access (take for example running as a guest user). Another issue that comes into play is creating it with the proper MutexAccessRule so that another user can access it after it is created. Code sample in 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);
}

The above code will create a mutex that is not restricted to the user that created it, this is important if you are in a terminal services environment with multiple people running the same program at the same time. You may be okay restricting some of the permissions more than I did there (really I create it with almost no restrictions), but without that you can have person A create the mutex and person B throw an exception because they can't access the mutex created by person A.

新雨望断虹 2024-10-10 03:12:55

是的,这是一个不好的做法。我浏览了这个问题几次,但我觉得自己的信息不够丰富,无法给出一个好的答案。这是一个问题,如果你不能轻松地解释你的锁定模型,并且你很难想出一张清晰的图片,那么推理可能的状态排列的数量也变得非常困难。

无法推理所有可能的状态排列可能会带来非常严重的运行时损失。僵局。

Yes, it is a bad practice. I scanned the question a few times but I don't exactly feel informed well enough to give a good answer. That's a problem, if you can't easily explain your locking model and you've got trouble coming up with a good picture that makes it clear then it also becomes very difficult to reason about the number of possible state permutations.

Not being able to reason about all possible state permutations has a potentially very nasty runtime penalty. Deadlock.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文