如何防止另一个线程在运行方法时修改方法中的局部引用变量

本文关键字:方法 局部 引用 变量 修改 线程 另一个 运行 何防止 | 更新日期: 2023-09-27 18:05:23

如何防止引用类型变量"local"内部方法"test"从中途改变,而它正在工作?除了深度复制,还有别的方法吗?我还认为"锁"应该防止这种情况发生,但在这种情况下没有。有人能开导我吗?

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication3
{
    class Class1
    {
        public int Value = 0;
    }
    class Test
    {
        private static readonly object m_lock = new object(); 

        static void Main()
        {
            Class1 r1 = new Class1();
            r1.Value = 2;
            Console.WriteLine("MainThread Original Value: {0} ", r1.Value);
            ThreadStart starter = delegate { test(r1); };
            Thread subThread = new Thread(starter);
            subThread.Start();
            Thread.Sleep(1000);
            r1.Value = 1234;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);
            Thread.Sleep(1000);
            r1.Value = 4321;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);
            Thread.Sleep(1000);
            r1.Value = 5678;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);

        }
        static void test(Class1 r)
        {
            lock (m_lock)
            {
                Class1 local = r;
                Console.WriteLine("SubThread Original Values: {0}, {1}", local.Value, r.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("SubThread Final Values: {0}, {1}", local.Value, r.Value);
                Console.ReadLine();
            }
        }
    }
}
输出:

MainThread Original Value: 2
SubThread Original Values: 2, 2
Working... local value: 2
MainThread New Value: 1234
Working... local value: 1234
Working... local value: 1234
MainThread New Value: 4321
Working... local value: 4321
Working... local value: 4321
MainThread New Value: 5678
Working... local value: 5678
Working... local value: 5678
SubThread Final Values: 5678, 5678

我想要达到的输出(其中"local"不会受到主线程中发生的事情的影响):

MainThread Original Value: 2
SubThread Original Values: 2, 2
Working... local value: 2
MainThread New Value: 1234
Working... local value: 2
Working... local value: 2
MainThread New Value: 4321
Working... local value: 2
Working... local value: 2
MainThread New Value: 5678
Working... local value: 2
Working... local value: 2
SubThread Final Values: 2, 5678

编辑:假设Class1不能修改,即它来自外部dll。

如何防止另一个线程在运行方法时修改方法中的局部引用变量

添加锁在这里没有帮助。这里只有Class1的一个实例,所以所有线程都访问这个对象。您需要为每个线程创建一个Class1实例,以便每个线程只有自己的Class1实例可以使用。

具体来说,test中读取Class1 local = r;的行是罪魁祸首。如果你将这一行改为Class1 local = new Class1(),那么你将得到你所期望的行为。

或者,从Main()传入一个新的Class1实例到test,除了您已经传入的实例之外。结果是一样的。如果您希望在将其传递给线程函数之前预先设置值,请执行以下操作:

static void Main()
    {
        Class1 r1 = new Class1();
        r1.Value = 2;
        Console.WriteLine("MainThread Original Value: {0} ", r1.Value);
        Class1 r2 = new Class1();
        r2.Value = 2;
        ThreadStart starter = delegate { test(r1, r2); };
        *rest of your code here*

对于static void test(Class1 r)使用

static void test(Class1 tr, Class1 r) {
    Class1 local = r;
    *etc*

请注意,这里我将r2而不是r1传递给test

这是你的代码,固定呈现相同的输出作为你正在寻找的:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication3 {
    class Class1 {
        public int Value = 0;
    }
    class Test {
        private static readonly object m_lock = new object();

        static void Main() {
            Class1 r1 = new Class1();
            r1.Value = 2;
            Class1 r2 = new Class1();
            r2.Value = 2;
            Console.WriteLine("MainThread Original Value: {0} ", r1.Value);
            ThreadStart starter = delegate { test(r1, r2); };
            Thread subThread = new Thread(starter);
            subThread.Start();
            Thread.Sleep(1000);
            r1.Value = 1234;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);
            Thread.Sleep(1000);
            r1.Value = 4321;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);
            Thread.Sleep(1000);
            r1.Value = 5678;
            Console.WriteLine("MainThread New Value: {0} ", r1.Value);

        }
        static void test(Class1 r, Class1 tr) {
            lock (m_lock) {
                Class1 local = tr;
                Console.WriteLine("SubThread Original Values: {0}, {1}", local.Value, r.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("Working... local value: {0}", local.Value);
                Thread.Sleep(500);
                Console.WriteLine("SubThread Final Values: {0}, {1}", local.Value, r.Value);
                Console.ReadLine();
            }
        }
    }
}

输出:

MainThread Original Value: 2
SubThread Original Values: 2, 2
Working... local value: 2
MainThread New Value: 1234
Working... local value: 2
Working... local value: 2
MainThread New Value: 4321
Working... local value: 2
Working... local value: 2
MainThread New Value: 5678
Working... local value: 2
Working... local value: 2
SubThread Final Values: 2, 5678