C#threading - 锁定对象

时间:2009-08-17 11:05:48

标签: c# multithreading locking

我想在c#app中锁定一个“盒装”对象,这是不可能的?

    class t
    {
        System.Object t_x = new object();

        public t(int p)
        {
            t_x = p;

        }

        public void w()
        {
            lock (t_x)
            {
                for (int i = 0; i < 4; i++)
                {

                    {
                        t_x = ((int)t_x) + 1;
                        Console.WriteLine(t_x);
                        Thread.Sleep(1000);
                    }
                }
            }
        }
    }

在另一个课程中,我可以开始2个主题:

        Thread b1 = new Thread(new ThreadStart(t1.w));
        b1.Start();
        Thread b2 = new Thread(new ThreadStart(t1.w));
        b2.Start();

然而该部分未被锁定。 当我锁定一个任意对象(即一个被创建但未被修改为对象a = new object())时,它会很好地锁定。 拳击操作不知何故“depromotes”我的对象??

6 个答案:

答案 0 :(得分:23)

不,你不能这样做 - 锁定块是以下的简写:

try(Monitor.Enter(lockObject))
{
    //critical section
}
finally
{
    Monitor.Exit(lockObject)
}

documentation for Monitor.Enter状态,“使用Monitor来锁定对象(即引用类型),而不是值类型。当您将值类型变量传递给Enter时,它将被设置为对象。如果您通过了同一个变量再次输入,它被装箱为一个单独的对象,并且该线程不会阻止“

答案 1 :(得分:17)

您需要创建一个单独的锁定对象。问题是你在循环中重新分配t_x。假设线程b1在b2到达lock语句之前进入循环,则b2将被允许在lock语句中,因为到那时,t_x将是一个没有锁定的新对象。

答案 2 :(得分:2)

您必须使用额外的对象来锁定

object lockObj = new object();
public void foo()
{
    lock(lockObj)
    {
    //do stuff here
    }
}

答案 3 :(得分:2)

lock(t_x)调用将整数作为临时对象。每次调用lock(t_x)都会创建一个New对象,锁定也没用。

(Lock需要一个对象并从整数中创建一个新的临时对象)

只需像Femaref那样创建一个单独的锁定对象。

答案 4 :(得分:0)

如果你真的想(需要?)锁定对象,你可以使用一种包装器:

public class IntWrapper
{
    public int Value{get;set;}
}

或者如果你需要更加抽象:

public class ObjectWrapper
{
    public Object Value { get;set; }
}

答案 5 :(得分:0)

如果您想要识别加载数据的时间,以及在此之前用户是否尝试使用它,您可以执行以下操作:

有一个像你提到的布尔标志,但在访问它之前使用一个单独的对象来锁定,以防止跨线程竞争条件。

当用户尝试使用数据时,如果未加载(检查变量),则可以向工作者RunWorkerCompleted事件添加另一个事件处理程序,该事件将立即执行用户在加载数据时所需的内容。

示例:

public class MyClass
{
    private bool dataIsReady = false;
    private object locker = new object();
    BackgroundWorker worker;

    public void Begin()
    {
        worker = new BackgroundWorker();
        worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
    }

    public void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        lock (locker)
        {
            dataIsReady = true;
        }
    }

    public void UseTriesToUseData()
    {
        lock (locker)
        {
            if (dataIsReady)
            {
                DoStuff();
            }
            else
            {
                this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(DoStuffCaller);
            }
        }
    }

    private void DoStuff()
    {
        // Do stuff with data.
    }

    private void DoStuffCaller(object sender, RunWorkerCompletedEventArgs e)
    {
        this.DoStuff();
    }
}