[!!!help!!!] 线程同步,互斥锁lock的问题...lock为何不起作用???愚翁,速马等老大请进... [!!!help!!!]

lj915 2006-08-09 01:08:13
写了一个简单的测试程序,发现有些很迷惑的地方...

先贴出程序的主要部分:

private System.Windows.Forms.Button button1;

private Object syncObj;

private Thread t1;
private Thread t2;

private volatile bool runT1;
private volatile bool runT2;

private void Form1_Load(object sender, System.EventArgs e)
{
syncObj = new object();

runT1 = true;
runT2 = true;
}

private void testObj()
{
syncObj = "t1";
}

private void testT1()
{
Console.WriteLine("t1 started");

lock(syncObj)
{
Console.WriteLine("t1 locked syncObj");

while(runT1)
{
//syncObj = "t1";

Thread.Sleep(1000);
}
}
}

private void testT2()
{
Console.WriteLine("t2 started");

Thread.Sleep(1000);

while(runT2)
{
lock(syncObj)
{
Console.WriteLine("t2 locked syncObj");

Thread.Sleep(1000);
}
}
}


private void button1_Click(object sender, System.EventArgs e)
{
runT1 = true;
runT2 = true;

t1 = new Thread(new ThreadStart(testT1));
t2 = new Thread(new ThreadStart(testT2));

t1.Name = "t1";
t2.Name = "t2";

t1.IsBackground = true;
t2.IsBackground = true;

t1.Start();
t2.Start();

button1.Enabled = false;
}

在线程t1一开始就已经锁住了syncObj,要知道t1退出才会释放syncObj的锁,这个时候t2才能够获得syncObj的锁,

上面的代码实现了上面所说的逻辑,输出:
t1 started
t1 locked syncObj
t2 started

但是如果将testT1()中被屏蔽的语句“syncObj = "t1";” 取消屏蔽,
程序就会出现t1在lock(syncObj)的期间,只要一修改sycnObj的值,
t2马上就可以获得syncObj的锁...
输出:
t1 is start
t1 locked syncObj
t2 is start
t2 locked syncObj
t2 locked syncObj
t2 locked syncObj
t2 locked syncObj
t2 locked syncObj
...
...
<程序退出>

在t1的生存期内,一直都没有释放过syncObj的锁,
但是只要一修改它的值,t2就可以获取它的锁并对其进行操作呢?
...全文
721 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
hxshanji 2007-04-24
  • 打赏
  • 举报
回复
mark...
lucyandqq 2006-12-13
  • 打赏
  • 举报
回复
mark
immc1979 2006-11-03
  • 打赏
  • 举报
回复
关注一下,免得日后找不到了
lj915 2006-08-09
  • 打赏
  • 举报
回复
to shuo_shu(取个名字还真难):

呵呵...明白你的意思了.
shuo_shu 2006-08-09
  • 打赏
  • 举报
回复
其实我的意思就是你在第一个Thread上面将syncObj改变到另一个引用上面去了(字符串是一个特殊的引用类型).
而第二个Thread这个时候才执行, 导致第二个Thread, lock的是新的syncObj.也就是那个字符串.
所以他们两个不是lock的同一个, 达不到lock的效果.

当然愚翁的是正解, 这个勿庸置疑. 我想表达的是, 当我们在使用lock去锁一个引用类型的时候,应该注意, 我们锁的是不是同一个引用. 虽然是同一个变量. 但是有可能不是一个引用的内存块了.
lj915 2006-08-09
  • 打赏
  • 举报
回复
to KDE(黎明) :

这里不是静态不静态的问题,本身syncObj就是全部变量.

对t1和t2两个线程来说,是同一个变量.

lj915 2006-08-09
  • 打赏
  • 举报
回复
Knight94(愚翁) ( ) 信誉:110 2006-8-9 16:34:32 得分: 0



to 为何将赋值放在sleep后面就会锁定同一个值呢?不是很理解,望指教指教...

这是sleep造成的执行顺序的变化,也就是线程进入lock区的先后顺序发生变化所造成的现象。

不是问题的根本原因。

>>>>>>>

刚才仔细想了一想,发现的确是这么一回事,看起来程序是正常运行,但是t1退出之后,t2仍然无法获得它想得到的锁,所以一直阻塞...根本原因还是 愚大大 所说的问题所引起的.
lj915 2006-08-09
  • 打赏
  • 举报
回复
shuo_shu(取个名字还真难) :

呵呵...我明白你的意思了,不过就算"赋值放在sleep后面"后面,程序还是会出错的,t2会陷入无止境的阻塞的.
KDE 2006-08-09
  • 打赏
  • 举报
回复
private Object syncObj;//不是共享的,当然锁不住了

t1和t2都各自拥有自己的syncObj

应该改为:

private static object syncObj;
Knight94 2006-08-09
  • 打赏
  • 举报
回复
to 为何将赋值放在sleep后面就会锁定同一个值呢?不是很理解,望指教指教...

这是sleep造成的执行顺序的变化,也就是线程进入lock区的先后顺序发生变化所造成的现象。

不是问题的根本原因。
lj915 2006-08-09
  • 打赏
  • 举报
回复
愚翁果真强人也.
你如果把赋值放在sleep后面, 那么他们锁定的就是一个值了.
因为还没有来得急将syncObj赋上新值, 第二个Thread已经运行起来了.

>>>

为何将赋值放在sleep后面就会锁定同一个值呢?不是很理解,望指教指教...
mmens 2006-08-09
  • 打赏
  • 举报
回复
Mark
shuo_shu 2006-08-09
  • 打赏
  • 举报
回复
愚翁果真强人也.
你如果把赋值放在sleep后面, 那么他们锁定的就是一个值了.
因为还没有来得急将syncObj赋上新值, 第二个Thread已经运行起来了.

lj915 2006-08-09
  • 打赏
  • 举报
回复
我的意思是说,需要被同步访问的是"代码段"而不是所传入的"对象",所以不是很理解为何要传一个对象(大多数情况,我都会锁定一个全局变量xxxobj = new object()这样的对象),这个对象又可能大多数情况下跟下面锁定的代码没有任何关系.

或者它是作为标记的手段吧...因为毕竟需要一个标记来表明该代码段已经被某个线程锁定了.

而能够有效表达出这个意思的,就是某线程已经获得了"对象"的锁,之后就可以判断任意访问到该代码段的线程是否有权执行该代码.

呵呵...也可以说,所传的"对象"是一把钥匙...不过看起来总觉得怪怪的
Knight94 2006-08-09
  • 打赏
  • 举报
回复
to 特别是lock,因为要锁定的是一段代码,为什么一定要传一个引用类型的对象呢?

这是对的,毕竟值类型变量的copy太平凡了。
lj915 2006-08-09
  • 打赏
  • 举报
回复
其实线程互斥或者同步问题,最多也就是对临界区的问题。
所以对于lock或者monitor中对于锁对象这部分,总是不那么信任(而且我记得有篇文章说过lock有问题)。

不过这也只是我个人的观点。

>>>

特别是lock,因为要锁定的是一段代码,为什么一定要传一个引用类型的对象呢?按照MSDN的说法"lock 关键字可将语句块标记为临界区",对象应该是"语句块"...跟所传的对象究竟有什么关系...
lj915 2006-08-09
  • 打赏
  • 举报
回复
对于lock和monitor来说都是解决线程互斥或者同步的问题,没有太严格的区分,不过相对于lock来说,monitor的功能会更强大一些。

>>>

个人认为lock关键字实现的功能,其实就是简单的
try
{
Monitor.Enter(x); ...
}
catch
{
...
}
finally
{
Monitor.Exit(x);
}
的封装(就象TcpListener/TcpClient是Socket的为达到某种特定操作而作的封装一样),但缺少了Monitor的TryEnter,Wait,Pulse等等的方法,所以应用上比较适用与锁定一写代码区域,所以在MSDN上也就说lock是用来锁定代码段的.

不知道我的猜想对不对呢?
Knight94 2006-08-09
  • 打赏
  • 举报
回复
其实线程互斥或者同步问题,最多也就是对临界区的问题。
所以对于lock或者monitor中对于锁对象这部分,总是不那么信任(而且我记得有篇文章说过lock有问题)。

不过这也只是我个人的观点。
lj915 2006-08-09
  • 打赏
  • 举报
回复
怀疑?请问 愚大大 的怀疑是怀疑什么东东呢?
Knight94 2006-08-09
  • 打赏
  • 举报
回复
其实我对于锁对象的操作一直表示怀疑。
加载更多回复(14)

110,545

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧