4

Lock没有按预期工作,这是代码。我在这里应用线程,但我会将它应用到ASP.NET应用程序。

class Program
    {
        static void Main(string[] args)
        {
            ThreadManager.CurrentSession = 0;
            for (int i = 0; i < 10; i++)
            {
                CreateWork objCreateWork = new CreateWork();
                ThreadStart start = new ThreadStart(objCreateWork.ProcessQuickPLan);
                new Thread(start).Start();
            }
            Console.ReadLine();
        }
    }

    class CreateWork
    {
        private object CurrentSession = -1;
        public void ProcessQuickPLan()
        {
            lock (CurrentSession)
            {
                CurrentSession = ThreadManager.CurrentSession;
                Console.WriteLine(CurrentSession);
                ThreadManager.CurrentSession = Convert.ToInt32(ThreadManager.CurrentSession) + 1;
            }
        }
    }

    class ThreadManager
    {
        public static object CurrentSession
        {
            get;
            set;
        }
    }

它给了我以下输出

0
0
0
3
4
4
6
7
8
9

我期待着

0
1
2
3
4
5
6
7
8
9

我在哪里做错了?

我应该readonly object按照这里的描述 使用C# lock(mylocker) not work

4

5 回答 5

3

问题在于您用来锁定的对象。您正在使用实例变量,因此每个实例都有自己的lock,这从根本上是错误的。

第二个问题是初始化-1,这至少令人困惑。

简单的解决方案是static object CurrentSession = new object();

下一个问题是CurrentSession = ThreadManager.CurrentSession;。这是没有意义的,本质上是错误的。我很惊讶它甚至可以编译。

class CreateWork
{
    private object CurrentSession = -1;   // boxed int, Id only
    private static object _locker = new object();

    public void ProcessQuickPLan()
    {
        lock (_locker)
        {
            CurrentSession = ThreadManager.CurrentSession;
            Console.WriteLine(CurrentSession);
            ThreadManager.CurrentSession = Convert.ToInt32(ThreadManager.CurrentSession) + 1;
        }
    }
}

摘要:目前尚不清楚您要在这里做什么。CurrentSession 似乎具有锁定保护和 Id 的双重作用。不是一个好计划。

基本上,您需要 1 个私有静态对象来保护资源。初始化后永远不要分配给它。

于 2013-08-09T10:31:44.130 回答
2

问题是您的每个线程都有自己的锁。制作CurrentSession静态应该可以解决问题:将只有一个对象可以锁定。您还应该停止在代码中重新分配它。

class CreateWork
{
    private static readonly object LockObject = -1; // Although -1 works here, it's really misleading
    // You should consider replacing the above with a "plain" new object();
    private object CurrentSession = -1; 
    public void ProcessQuickPLan()
    {
        lock (LockObject)
        {
            CurrentSession = ThreadManager.CurrentSession;
            Console.WriteLine(CurrentSession);
            ThreadManager.CurrentSession = Convert.ToInt32(ThreadManager.CurrentSession) + 1;
        }
    }
}

这是关于 ideone 的工作演示

于 2013-08-09T10:33:44.480 回答
0

将您的代码更改为:

using System;
using System.Threading;
class Program
{
    static void Main(string[] args)
    {
        ThreadManager.CurrentSession = 0;
        for (int i = 0; i < 10; i++)
        {
            CreateWork objCreateWork = new CreateWork();
            ThreadStart start = new ThreadStart(objCreateWork.ProcessQuickPLan);
            new Thread(start).Start();
        }
        Console.ReadLine();
    }
}

class CreateWork
{
    private static object _lock = new Object();

    public void ProcessQuickPLan()
    {
        lock (_lock)
        {            
            Console.WriteLine(ThreadManager.CurrentSession);
            ThreadManager.CurrentSession++;
        }
    }
}

class ThreadManager
{
    public static int CurrentSession
    {
        get;
        set;
    }
}

重要的是您的锁定和跟踪您的身份之间的分离。

私有锁是一个静态对象,因此它在线程之间共享。我还删除了每次为锁分配一个新值。

于 2013-08-09T10:48:02.150 回答
0

我认为问题在于,您将对象锁定在自己的线程中,因此它永远不会真正锁定。

更好地使用全局对象,它将被锁定。

于 2013-08-09T10:32:53.223 回答
0

每个线程都包含自己的CreateWork带有储物柜的实例。试试这个代码:

class Program
{
    static void Main(string[] args)
    {
        ThreadManager.CurrentSession = 0;
        CreateWork objCreateWork = new CreateWork();
        for (int i = 0; i < 10; i++)
        {
            ThreadStart start = new ThreadStart(objCreateWork.ProcessQuickPLan);
            new Thread(start).Start();
        }
        Console.ReadLine();
    }
}

class CreateWork
{
    private object CurrentSession = -1;
    public void ProcessQuickPLan()
    {
        lock (CurrentSession)
        {
            CurrentSession = ThreadManager.CurrentSession;
            Console.WriteLine(CurrentSession);
            ThreadManager.CurrentSession = Convert.ToInt32(ThreadManager.CurrentSession) + 1;
        }
    }
}

class ThreadManager
{
    public static object CurrentSession
    {
        get;
        set;
    }
}
于 2013-08-09T10:35:05.847 回答