6

我编写了一个静态类,它是我从不同类调用的一些函数的存储库。

public static class CommonStructures
{
    public struct SendMailParameters
    {
        public string To { get; set; }
        public string From { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }
        public string Attachment { get; set; }
    }
}

public static class CommonFunctions
{
    private static readonly object LockObj = new object();
    public static bool SendMail(SendMailParameters sendMailParam)
    {
        lock (LockObj)
        {
            try
            {
                //send mail
                return true;
            }
            catch (Exception ex)
            {
                //some exception handling
                return false;
            }
        }
    }

    private static readonly object LockObjCommonFunction2 = new object();
    public static int CommonFunction2(int i)
    {
        lock (LockObjCommonFunction2)
        {
            int returnValue = 0;
            try
            {
                //send operation
                return returnValue;
            }
            catch (Exception ex)
            {
                //some exception handling
                return returnValue;
            }
        }
    }
}

问题1:对于我的第二种方法CommonFunction2,我是使用一个新的静态锁,即本例中的LockObjCommonFunction2,还是可以重复使用在函数开头定义的同一个锁对象LockObj。

问题 2:是否有任何可能导致线程相关问题的内容,或者我可以将代码改进为安全线程。

问题 3:在这个例子中传递公共类而不是结构会有什么问题吗 SendMailParameters(我利用包装所有参数,而不是为 SendMail 函数提供多个参数)?

问候, MH

4

4 回答 4

5

问题1:对于我的第二种方法CommonFunction2,我是使用一个新的静态锁,即本例中的LockObjCommonFunction2,还是可以重复使用在函数开头定义的同一个锁对象LockObj。

如果要同步这两种方法,则需要为它们使用相同的锁。例如,如果 thread1 正在访问您的 Method1,而 thread2 正在访问您的 Method2,并且您希望它们不要同时访问两个内部,请使用相同的 lock。但是,如果您只想限制对Method1 或 2 的并发访问,请使用不同的 locks

问题 2:是否有任何可能导致线程相关问题的内容,或者我可以将代码改进为安全线程。

永远记住,共享资源(例如静态变量、文件)不是线程安全的,因为它们很容易被所有线程访问,因此您需要应用任何类型的同步(通过锁、信号、互斥锁等)。

问题 3:在这个例子中传递公共类而不是结构会有什么问题吗 SendMailParameters(我利用包装所有参数,而不是为 SendMail 函数提供多个参数)?

只要您应用适当的同步,它将是线程安全的。对于结构,请将此作为参考。

底线是您需要对共享内存中的任何内容应用正确的同步。此外,您应该始终注意您正在生成的线程的范围以及每个方法正在使用的变量的状态。它们是改变状态还是仅仅依赖于变量的内部状态?线程是否总是创建一个对象,尽管它是静态/共享的?如果是,那么它应该是线程安全的。否则,如果它只是重​​用某个共享资源,那么您应该应用适当的同步。最重要的是,即使没有共享资源,死锁仍然可能发生,因此请记住 C# 中的基本规则以避免死锁PS感谢 Euphoric 分享 Eric Lippert 的文章。

但要小心你的同步。尽可能将它们的范围限制在共享资源被修改的地方。因为它可能会给您的应用程序带来不便的瓶颈,从而极大地影响性能。

    static readonly object _lock = new object();
    static SomeClass sc = new SomeClass();
    static void workerMethod()
    {
        //assuming this method is called by multiple threads

        longProcessingMethod();

        modifySharedResource(sc);
    }

    static void modifySharedResource(SomeClass sc)
    {
        //do something
        lock (_lock)
        {
            //where sc is modified
        }
    }

    static void longProcessingMethod()
    {
        //a long process
    }
于 2013-06-07T06:03:23.167 回答
0

您可以根据需要多次重用同一个锁对象,但这意味着不同线程不能同时访问被同一个锁包围的任何代码区域。因此,您需要相应地进行计划,并仔细考虑。

例如,如果有多个函数编辑同一个数组,有时最好将一个锁对象用于多个位置。其他时候,多个锁对象更好,因为即使一段代码被锁定,另一段代码仍然可以运行。

多线程编码都是关于仔细规划...

为了超级安全,以可能编写更慢的代码为代价......您可以将访问器添加到由锁包围的静态类。这样,您可以确保该类的任何方法都不会被两个线程同时调用。这是相当蛮力的,对于专业人士来说绝对是“禁忌”。但是,如果您只是熟悉这些东西的工作原理,那么开始学习并不是一个糟糕的地方。

于 2013-06-07T05:17:25.870 回答
0

1)至于首先取决于你想要什么:

照原样(两个单独的锁对象) - 没有两个线程会同时执行相同的方法,但它们可以同时执行不同的方法。

如果您更改为具有单个锁定对象,则没有两个线程将在共享锁定对象下执行这些部分。

2)在您的代码段中,没有什么让我觉得是错误的——但代码不多。如果您的存储库从自身调用方法,那么您可能会遇到问题,并且您可能会遇到很多问题:)

3)至于结构,我不会使用它们。使用类会更好/更容易,这样会有另一袋与结构相关的问题,你只是不需要这些问题。

于 2013-06-07T05:26:09.093 回答
0

要使用的锁定对象的数量取决于您要保护的数据类型。如果您有多个在多个线程上读取/更新的变量,则应为每个自变量使用单独的锁定对象。因此,如果您有 10 个变量组成 6 个自变量组(就您打算如何读取/写入它们而言),您应该使用 6 个锁定对象以获得最佳性能。(自变量是在多个线程上读取/写入而不影响其他变量的值的变量。如果必须为给定的操作一起读取 2 个变量,则它们相互依赖,因此必须将它们锁定在一起。我希望这不会太混乱。)

锁定区域应尽可能短以获得最佳性能 - 每次锁定代码区域时,在释放锁定之前没有其他线程可以进入该区域。如果您有许多自变量但使用的锁对象太​​少,您的性能将会受到影响,因为您的锁定区域会变得更长。

拥有更多的锁对象可以实现更高的并行性,因为每个线程都可以读取/写入不同的自变量 - 如果线程尝试读取/写入相互依赖的变量(因此通过相同的锁定对象)。

在你的代码中,你必须小心你的SendMailParameters输入参数——如果这是一个引用类型(类,而不是结构),你必须确保它的属性被锁定或者它不是在多个线程上访问的。如果它是引用类型,它只是一个指针,并且没有在其属性 getter/setter 内锁定,多个线程可能会尝试读取/写入同一实例的某些属性。如果发生这种情况,您的SendMail()函数最终可能会使用损坏的实例。仅仅在内部有一个锁是不够的SendMail()- 的属性和方法也SendMailParameters必须受到保护。

于 2013-06-07T05:27:43.737 回答