首页 新闻 会员 周边 捐助

递归算法中的多线程lock锁问题

0
悬赏园豆:20 [已解决问题] 解决于 2013-03-08 10:47

这个问题是从别人昨天提问的一个问题上扩展过来的,是一个面试题,题目如下。

根据线程安全的相关知识,分析一下代码,当调用test方法时i>10时是否会引起死锁

   public void test(int i)
        {
            lock (this)
            {
                if (i > 0)
                {
                    i--;
                    test(i);
                }
            }
        }

答:不会发生死锁,(但有一点int是按值传递的,所以每次改变的都只是一个副本,因此不会出现死锁。但如果把int换做一个object,那么死锁会发生)

答案是错的大家不用管它,在单线程环境下无论怎么还参数都不可能发生死锁问题的。网上找了下资料后发现重点应该是这句话“lock只会生效于多线程,对于单线程,自身已经是锁的所有者,并不会出现为了继续加锁等待原有锁释放”。但是我做了这么一个测试。

 static void Main(string[] args)
        {
            Program p = new Program();
            MyObj obj = new MyObj();
            //第一个线程
            Thread thread1 = new Thread(p.test);
            thread1.Name = "thread1";
            //第一个线程
            Thread thread2 = new Thread(p.test);
            thread2.Name = "thread2";
            //启动线程
            thread1.Start(obj);
            thread2.Start(obj);
            Console.Read();
        }

        public void test(object obj)
        {
            lock (this)
            {
                if (((MyObj)obj).value > 10)
                {
                    ((MyObj)obj).value--;
                    Console.Write(Thread.CurrentThread.Name + ":");
                    Console.WriteLine(((MyObj)obj).value);
//子线程中再创建一个线程 Thread t
= new Thread(test); t.Name = "t" + ((MyObj)obj).value.ToString(); t.Start(obj); } else { Console.WriteLine(Thread.CurrentThread.Name); } } }

这个测试的结果是,Thread2会被Thread1的锁锁住导致无法访问里面的代码,但是Tread1里面新建的所有的t线程却全部可以访问这个lock锁里的内容。这个结果很奇怪,是否从线程a中创建的线程b会和创建它的线程a有某种联系?我找了下相关资料,应用程序域跟对象上下文之类的,貌似不是这个的问题,望对这些比较低层东西有了解的大神坐下解答。

问题补充:

线程a中创建的线程可以访问这个线程a的锁 但是跟线程a一起创建的线程b却没法访问 归纳一下就是这么个问题..

林J的主页 林J | 菜鸟二级 | 园豆:202
提问于:2013-03-08 09:41
< >
分享
最佳答案
0

线程重入问题,lock会与线程关联,如关联上A1线程,那么A1线程重复进入多次也是OK的。但是lock又是独占锁,所以一旦关联上线程,别的线程就无法进入lock代码块。

还可参考下:http://q.cnblogs.com/q/47255/

收获园豆:20
滴答的雨 | 老鸟四级 |园豆:3660 | 2013-03-08 09:57

但是A1线程创建的其他线程(就是我上面的t)却可以进去啊。

林J | 园豆:202 (菜鸟二级) | 2013-03-08 09:58

我的问题就是从那个问题上面扩展过来的,注意在test方法中创建了新线程 并且这些新线程可以访问这个lock里面的东西 我的疑惑是这里

林J | 园豆:202 (菜鸟二级) | 2013-03-08 09:59

@林J: 这个子线程之前看的时候倒是没注意这个细节,如果依你这样的情况,我只能想到原因是:每当一个线程(初始线程)使用另一个线程(辅助线程)执行任务时,CLR会将前者的执行上下文流向(复制到)辅助线程。这就确保了辅助线程执行的任何操作使用的是相同的安全设置和宿主设置。还确保了初始线程的逻辑调用上下文可以在辅助线程中使用。(继承而来的设置相同吧)

异步编程:使用线程池管理线程

滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-08 10:07

@滴答的雨: 例子我帮你改了下,你试试。和我最开始回答的结果一致,是与线程关联的。。。之所以子线程进去了,其实是因为其他线程已经退出了lock块

        public void test(object obj)
        {
            lock (this)
            {
                if (((MyObj)obj).value > 10)
                {
                    ((MyObj)obj).value--;
                    Console.WriteLine("进入:"+Thread.CurrentThread.Name);
                    //子线程中再创建一个线程
                    Thread t = new Thread(test);
                    t.Name = Thread.CurrentThread.Name+">"+"t" + ((MyObj)obj).value.ToString();
                    t.Start(obj);
                }
                else
                {
                    Console.WriteLine("else:"+Thread.CurrentThread.Name);
                }
            }
            Console.WriteLine("over:" + Thread.CurrentThread.Name);
        }

滴答的雨 | 园豆:3660 (老鸟四级) | 2013-03-08 10:27

@滴答的雨: 啊,是我想太多了,确实是因为其他线程退出来了,当test(obj)是单线程时,后面的代码要等到这个递归里的所有循环都结束后才能执行到,但是由于这是多线程的,它可以直接执行到最后面了。

lock只会生效于多线程,对于单线程,自身已经是锁的所有者,并不会出现为了继续加锁等待原有锁释放”这句话还是适用的,太感谢你了!!!

林J | 园豆:202 (菜鸟二级) | 2013-03-08 10:47
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册