using System.Threading;
using System.Diagnostics;
class App
{
public int i=0, j=0;
public int Limit = 1000;
public void Increase()
{
while(i < Limit)
{
try
{
Monitor.Enter(this);
i++;
Thread.Sleep(1);
j++;
}
finally
{
Monitor.Exit(this);
}
}
}
public void Check()
{
while(i < Limit)
{
try
{
Monitor.Enter(this);
if(i != j)
{
Debug.WriteLine("i != j, i="+i+" j="+j);
Thread t = Thread.CurrentThread;
t.Abort();
}
}
finally
{
Monitor.Exit(this);
}
Thread.Sleep(1);
}
}
public static void Main()
{
App app = new App();
Thread t1 = new Thread(new ThreadStart(app.Increase));
Thread t2 = new Thread(new ThreadStart(app.Increase));
Thread t3 = new Thread(new ThreadStart(app.Check));
t1.Start();
t2.Start();
t3.Start();
}
}
有如上代码,请问Monitor.Enter(this)是监视App类的一个实例app还是只监视app的某个函数?例如app.Increase。据某本书上写着,Monitor.Enter(this)是监视app.Increase的,为了达到t3检测到i和j的值相等,第一步先要做的是在Increase函数里加上一个Monitor,以达到t1增加i和j的值时t2不能也来和t1同时对函数app.Increase操作,所以此时i和j的值总是相等,这个可以理解,但是书上又说这样是不够的,还会检测到i和j的值不等,其中一个原因就是当i加了1时,还没等到j加上1,app.Check就对i,j进行检测,而解决这个问题的办法是在Check里也加一个Monitor,最终就形成了上面的完整代码了。
我所不明白的是:在我理解,Check上没加Monitor和有加Monitor是没区别的,得到的都是i和j不相等,因为即使在Check加Monitor,它同样可以在Increase的i刚加1后检测i和j的值,Increase的Monitor只是保证此时不能有别的线程调用Increase函数,但不保证此时不能有别的线程访问i和j的值啊。
可是按照上面完整代码的运行结果,检测出的i和j永远是相等的,为什么呢?
10 个解决方案
#1
Monitor.Enter(this)应该是监视app对象的吧
#2
假如是app对象的话,问题又来啦,当t1开始运行后,如果是锁定app对象不能被其他线程读写的话,按道理Check不管是否有加Monitor,在t1运行时t3都不能访问app对象啊,当t1运行完毕后,t3 要访问app时,i和j的值必定相等。但为什么Check没加Monitor时检测到的i和j不等,但有加Monitor时检测到相等呢?
#3
呵呵,Int32最大是2,147,483,647
public int Limit = 1000;
-〉
public int Limit = 2000000000;
哥们的机器要是够BT,Monitor和不Monitor还一样,那这样:
//public int i=0, j=0;
//public int Limit = 1000;
public Int64 i=0, j=0;
public Int64 Limit = 9000000000000;
public int Limit = 1000;
-〉
public int Limit = 2000000000;
哥们的机器要是够BT,Monitor和不Monitor还一样,那这样:
//public int i=0, j=0;
//public int Limit = 1000;
public Int64 i=0, j=0;
public Int64 Limit = 9000000000000;
#4
此处是研究学术问题,不是讨论机器的性能问题,到目前为止本人还未得出确凿的结论为什么会出现以上的现象,对于以上一段代码又该如何去理解,请赐教。
#5
我希望得到的是一种不考虑机器性能的单纯的结论。
#6
using System;
using System.Threading;
using System.Diagnostics;
class App2
{
public int i=0, j=0;
public int Limit = 1000;
public void Increase()
{
while(i < Limit)
{
try
{
Console.WriteLine("Increase: Before Monitor.Enter(this)" + " --- " +Thread.CurrentThread.Name+"\n");
Monitor.Enter(this);
Console.WriteLine("Increase: After Monitor.Enter(this) Before i++"+" --- " + Thread.CurrentThread.Name+"\n");
i++;
Thread.Sleep(1);
j++;
Console.WriteLine(Thread.CurrentThread.Name+" Control The Object<App2> Successfully!"+" i="+i.ToString()+" j="+j.ToString()+"\n");
}
finally
{
Monitor.Exit(this);
}
}
}
public void Check()
{
try
{
Console.WriteLine("Check: Before Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
Monitor.Enter(this);
Console.WriteLine("Check:After Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
if(i != j)
{
Debug.WriteLine("i != j, i="+i+" j="+j);
Thread t = Thread.CurrentThread;
t.Abort();
}
}
finally
{
// Monitor.Exit(this);
}
Thread.Sleep(1);
}
static Thread t1,t2,t3;
public static void Main()
{
App2 app = new App2();
t1 = new Thread(new ThreadStart(app.Increase));
t2 = new Thread(new ThreadStart(app.Increase));
t3 = new Thread(new ThreadStart(app.Check));
t1.Name = "t1";
t2.Name = "t2";
t3.Name = "t3";
t1.Start();
t2.Start();
t3.Start();
Console.ReadLine();
}
}
楼主看看能不能帮你找找感觉
using System.Threading;
using System.Diagnostics;
class App2
{
public int i=0, j=0;
public int Limit = 1000;
public void Increase()
{
while(i < Limit)
{
try
{
Console.WriteLine("Increase: Before Monitor.Enter(this)" + " --- " +Thread.CurrentThread.Name+"\n");
Monitor.Enter(this);
Console.WriteLine("Increase: After Monitor.Enter(this) Before i++"+" --- " + Thread.CurrentThread.Name+"\n");
i++;
Thread.Sleep(1);
j++;
Console.WriteLine(Thread.CurrentThread.Name+" Control The Object<App2> Successfully!"+" i="+i.ToString()+" j="+j.ToString()+"\n");
}
finally
{
Monitor.Exit(this);
}
}
}
public void Check()
{
try
{
Console.WriteLine("Check: Before Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
Monitor.Enter(this);
Console.WriteLine("Check:After Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
if(i != j)
{
Debug.WriteLine("i != j, i="+i+" j="+j);
Thread t = Thread.CurrentThread;
t.Abort();
}
}
finally
{
// Monitor.Exit(this);
}
Thread.Sleep(1);
}
static Thread t1,t2,t3;
public static void Main()
{
App2 app = new App2();
t1 = new Thread(new ThreadStart(app.Increase));
t2 = new Thread(new ThreadStart(app.Increase));
t3 = new Thread(new ThreadStart(app.Check));
t1.Name = "t1";
t2.Name = "t2";
t3.Name = "t3";
t1.Start();
t2.Start();
t3.Start();
Console.ReadLine();
}
}
楼主看看能不能帮你找找感觉
#7
顶到最前面去
#8
up
#9
不会,问题太难啦
#10
我的理解是monitor锁定对象是为了告诉临界区的代码是属于哪个对象的。当前线程(获得对象锁的线程)使用这个对象执行临界区的代码。
当check没有使用monitor的时候,肯定会返回i<>j的情况。因为i和j是所有线程共享的对象,当t1线程修改了i,没有修改j的时候,这个时候t2线程没有获得对象锁阻塞,由于t3线程没有使用monitor,换句话说t3线程不必阻塞,就能直接访问i和j,显然这个时候i<>j。
当t3线程使用了monitor,则也会被阻塞。
当check没有使用monitor的时候,肯定会返回i<>j的情况。因为i和j是所有线程共享的对象,当t1线程修改了i,没有修改j的时候,这个时候t2线程没有获得对象锁阻塞,由于t3线程没有使用monitor,换句话说t3线程不必阻塞,就能直接访问i和j,显然这个时候i<>j。
当t3线程使用了monitor,则也会被阻塞。
#1
Monitor.Enter(this)应该是监视app对象的吧
#2
假如是app对象的话,问题又来啦,当t1开始运行后,如果是锁定app对象不能被其他线程读写的话,按道理Check不管是否有加Monitor,在t1运行时t3都不能访问app对象啊,当t1运行完毕后,t3 要访问app时,i和j的值必定相等。但为什么Check没加Monitor时检测到的i和j不等,但有加Monitor时检测到相等呢?
#3
呵呵,Int32最大是2,147,483,647
public int Limit = 1000;
-〉
public int Limit = 2000000000;
哥们的机器要是够BT,Monitor和不Monitor还一样,那这样:
//public int i=0, j=0;
//public int Limit = 1000;
public Int64 i=0, j=0;
public Int64 Limit = 9000000000000;
public int Limit = 1000;
-〉
public int Limit = 2000000000;
哥们的机器要是够BT,Monitor和不Monitor还一样,那这样:
//public int i=0, j=0;
//public int Limit = 1000;
public Int64 i=0, j=0;
public Int64 Limit = 9000000000000;
#4
此处是研究学术问题,不是讨论机器的性能问题,到目前为止本人还未得出确凿的结论为什么会出现以上的现象,对于以上一段代码又该如何去理解,请赐教。
#5
我希望得到的是一种不考虑机器性能的单纯的结论。
#6
using System;
using System.Threading;
using System.Diagnostics;
class App2
{
public int i=0, j=0;
public int Limit = 1000;
public void Increase()
{
while(i < Limit)
{
try
{
Console.WriteLine("Increase: Before Monitor.Enter(this)" + " --- " +Thread.CurrentThread.Name+"\n");
Monitor.Enter(this);
Console.WriteLine("Increase: After Monitor.Enter(this) Before i++"+" --- " + Thread.CurrentThread.Name+"\n");
i++;
Thread.Sleep(1);
j++;
Console.WriteLine(Thread.CurrentThread.Name+" Control The Object<App2> Successfully!"+" i="+i.ToString()+" j="+j.ToString()+"\n");
}
finally
{
Monitor.Exit(this);
}
}
}
public void Check()
{
try
{
Console.WriteLine("Check: Before Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
Monitor.Enter(this);
Console.WriteLine("Check:After Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
if(i != j)
{
Debug.WriteLine("i != j, i="+i+" j="+j);
Thread t = Thread.CurrentThread;
t.Abort();
}
}
finally
{
// Monitor.Exit(this);
}
Thread.Sleep(1);
}
static Thread t1,t2,t3;
public static void Main()
{
App2 app = new App2();
t1 = new Thread(new ThreadStart(app.Increase));
t2 = new Thread(new ThreadStart(app.Increase));
t3 = new Thread(new ThreadStart(app.Check));
t1.Name = "t1";
t2.Name = "t2";
t3.Name = "t3";
t1.Start();
t2.Start();
t3.Start();
Console.ReadLine();
}
}
楼主看看能不能帮你找找感觉
using System.Threading;
using System.Diagnostics;
class App2
{
public int i=0, j=0;
public int Limit = 1000;
public void Increase()
{
while(i < Limit)
{
try
{
Console.WriteLine("Increase: Before Monitor.Enter(this)" + " --- " +Thread.CurrentThread.Name+"\n");
Monitor.Enter(this);
Console.WriteLine("Increase: After Monitor.Enter(this) Before i++"+" --- " + Thread.CurrentThread.Name+"\n");
i++;
Thread.Sleep(1);
j++;
Console.WriteLine(Thread.CurrentThread.Name+" Control The Object<App2> Successfully!"+" i="+i.ToString()+" j="+j.ToString()+"\n");
}
finally
{
Monitor.Exit(this);
}
}
}
public void Check()
{
try
{
Console.WriteLine("Check: Before Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
Monitor.Enter(this);
Console.WriteLine("Check:After Monitor.Enter(this)"+"---" +Thread.CurrentThread.Name);
if(i != j)
{
Debug.WriteLine("i != j, i="+i+" j="+j);
Thread t = Thread.CurrentThread;
t.Abort();
}
}
finally
{
// Monitor.Exit(this);
}
Thread.Sleep(1);
}
static Thread t1,t2,t3;
public static void Main()
{
App2 app = new App2();
t1 = new Thread(new ThreadStart(app.Increase));
t2 = new Thread(new ThreadStart(app.Increase));
t3 = new Thread(new ThreadStart(app.Check));
t1.Name = "t1";
t2.Name = "t2";
t3.Name = "t3";
t1.Start();
t2.Start();
t3.Start();
Console.ReadLine();
}
}
楼主看看能不能帮你找找感觉
#7
顶到最前面去
#8
up
#9
不会,问题太难啦
#10
我的理解是monitor锁定对象是为了告诉临界区的代码是属于哪个对象的。当前线程(获得对象锁的线程)使用这个对象执行临界区的代码。
当check没有使用monitor的时候,肯定会返回i<>j的情况。因为i和j是所有线程共享的对象,当t1线程修改了i,没有修改j的时候,这个时候t2线程没有获得对象锁阻塞,由于t3线程没有使用monitor,换句话说t3线程不必阻塞,就能直接访问i和j,显然这个时候i<>j。
当t3线程使用了monitor,则也会被阻塞。
当check没有使用monitor的时候,肯定会返回i<>j的情况。因为i和j是所有线程共享的对象,当t1线程修改了i,没有修改j的时候,这个时候t2线程没有获得对象锁阻塞,由于t3线程没有使用monitor,换句话说t3线程不必阻塞,就能直接访问i和j,显然这个时候i<>j。
当t3线程使用了monitor,则也会被阻塞。