传递给静态方法的参数中的线程安全性

时间:2011-01-10 18:44:09

标签: asp.net multithreading parameters thread-safety

假设从ASP.NET页面调用如下的静态方法, 可以不同的线程(b)在线程(a)执行第一行之后覆盖s1的值吗?

如果是这样,可以在操作解决之前将参数分配给局部变量吗?

public static string TestMethod(string s1, string s2, string s3)
{
   s1 = s2 + s3;
   ....
   ...
   return s1;
}

是否有一种简单的方法可以重新创建与线程安全相关的问题?

感谢。

4 个答案:

答案 0 :(得分:4)

不,参数是局部变量 - 它们独立于任何其他线程。因为字符串也是不可变的,所以你是安全的。如果这些是可变的 - 例如参数StringBuilder s1 - 然后,虽然s1(引用)的无法更改,但参数引用的对象可能会更改其内容。

refout参数可能存在问题,因为它们可以对线程之间共享的变量进行别名。

答案 1 :(得分:1)

我也有同样的困惑,这是我的测试代码。只是分享它......

public partial class _default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        ThreadTest b = new ThreadTest();
        Thread t = new Thread(new ParameterizedThreadStart(ThreadTest.sum));
        Thread t1 = new Thread(new ParameterizedThreadStart(ThreadTest.sum));
        t.Start(10);
        t1.Start(12);

    }
}

class ThreadTest
{

    public static void sum(object XX)
    {
        int x = (int)XX;
        for (int i = 0; i < x; i++)
        {
            System.Diagnostics.Debug.WriteLine("max : " + x + "  ---  " + i.ToString());
        }
    }
}

...现在如果你运行它,你会发现int x是安全的。因此,本地非静态变量对于进程是安全的,并且不会被多线程瘫痪

答案 2 :(得分:0)

,在某些情况下,如示例代码所示。

public static class ConsoleApp {
    public static void Main() {
        Console.WriteLine("Write something.");
        var str = Console.ReadLine();
        if (String.IsNullOrEmpty(str))
            return;

        new Thread(() => TestMethod(null, str, "")).Start();

        // Allow TestMethod to execute.
        Thread.Sleep(100);

        unsafe {
            // Grab pointer to our string.
            var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned);
            var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer();

            // Change it, one character at a time, wait a little more than
            // TestMethod for dramatic effect.
            for (int i = 0; i < str.Length; ++i) {
                strPtr[i] = 'x';
                Thread.Sleep(1100);
            }
        }

        // Tell TestMethod to quit.
        _done = true;
        Console.WriteLine("Done.");
        Console.ReadLine();
    }

    private static Boolean _done;
    public static void TestMethod(String x, String y, String z) {
        x = y + z;

        while (!_done) {
            Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), x);
            Thread.Sleep(1000);
        }
    }
}

要求(afaik)

  1. 使用指针的不安全上下文。
  2. 使用String.Concat(String str0,String str1),它针对str0 == String.Emptystr1 == String.Empty的情况进行了优化,返回非空字符串。连接三个或更多字符串会创建一个新的字符串来阻止它。

  3. 以下是您修改过的修复版本。

    public static class ConsoleApp {
        private static Int32 _counter = 10;
    
        public static void Main() {
            for (var i = 0; i < 10; i++) {
                var str = GetString();
                Console.WriteLine("Input: {0} - {1}", DateTime.Now.ToLongTimeString(), str);
                new Thread(() => TestMethod(str)).Start();
    
                unsafe {
                    var gcHandle = GCHandle.Alloc(str, GCHandleType.Pinned);
                    var strPtr = (char*)gcHandle.AddrOfPinnedObject().ToPointer();
                    strPtr[0] = 'A';
                    strPtr[1] = 'B';
                    strPtr[2] = 'C';
                    strPtr[3] = 'D';
                    strPtr[4] = 'E';
                }
            }
    
            Console.WriteLine("Done.");
            Console.ReadLine();
        }
    
        private static String GetString() {
            var builder = new StringBuilder();
    
            for (var i = _counter; i < _counter + 10; i++)
                builder.Append(i.ToString());
    
            _counter = _counter + 10;
            return builder.ToString();
        }
    
        public static void TestMethod(Object y) {
            Thread.Sleep(2000);
            Console.WriteLine("Output: {0} {1}", DateTime.Now.ToLongTimeString(), y);
        }
    }
    

    这仍然有效,因为Object.ToString()在String中被覆盖以返回它,因此返回完全相同的引用。

答案 3 :(得分:0)

谢谢西蒙,这是我对此的评价。 在下面的代码中,我简单地使用Thread.Start生成线程,输出变得不一致。

这证明可以修改传递给方法的字符串。

如果不是,请解释

public static class ConsoleApp{

    [ThreadStatic]
    private static int counter = 10;

    public static void Main()
    {            
        string str;

        object obj = new object();
        // Change it, one character at a time, wait a little more than
        // TestMethod for dramatic effect.            
        for (int i = 0; i < 10; i++)
        {
            lock (obj)
            {
                str = GetString();
                Console.WriteLine(DateTime.Now.ToLongTimeString());
                //ThreadPool.QueueUserWorkItem(TestMethod, str);
                new Thread(() => TestMethod(str)).Start();
            }
        }

        Console.WriteLine("Done.");
        Console.ReadLine();
    }

    private static string GetString()
    {
        object obj = new object();
        lock (obj)
        {
            StringBuilder sb = new StringBuilder();
            int temp = 0;
            for (int i = counter; i < counter + 10; i++)
            {
                sb.Append(i.ToString());
                temp = i;
            }
            counter = temp;            
            return sb.ToString();
        }
    }

    public static void TestMethod(object y)
    {   
        Thread.Sleep(2000);
        Console.WriteLine("{0} {1}", DateTime.Now.ToLongTimeString(), y.ToString());
    }
}

感谢。