如何防止方法“test”中的引用类型变量“local”在工作时中途改变?除了制作它的深层副本之外,还有其他方法吗?我还认为“锁定”应该可以防止这种情况发生,但在这种情况下它不会发生。谁能开导我?
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。
答案 0 :(得分:1)
添加锁定在这里没有帮助。您这里只有一个Class1实例,因此所有线程都访问该单个对象。您需要为每个线程创建一个Class1实例,以便每个线程只有自己的Class1实例可供使用。
具体而言,test
中读取Class1 local = r;
的行是罪魁祸首。如果您将该行更改为阅读Class1 local = new Class1()
,那么您将获得所期望的行为。
或者,除了您已经传递的实例之外,从test
传入Main()
个新的Class1实例。那会做同样的事情。如果要在将值传递给线程函数之前预先设置值,请执行以下操作:
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