【文章标题】: 乱涂C#多线程05
【文章作者】: 有酒醉
【作者邮箱】: wuqr32@sina.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
记住,我们只能使用监督程序同步访问对象引用,而不是值类型.当Monitor.Enter接收值类型时,它首先将进行一次封箱,每一次封箱产生新的对象,这将不会导致同步访问.
【文章作者】: 有酒醉
【作者邮箱】: wuqr32@sina.com
【下载地址】: 自己搜索下载
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
记住,我们只能使用监督程序同步访问对象引用,而不是值类型.当Monitor.Enter接收值类型时,它首先将进行一次封箱,每一次封箱产生新的对象,这将不会导致同步访问.
示例 - 传递值类型
//
CValueTypeDemo.cpp
// Author by Yzl
# using < mscorlib.dll >
using namespace System;
using namespace System::Threading;
#pragma managed
__gc class CValueTypeDemo
... {
public:
static void ThreadProc(Object * state)
...{
Thread::Sleep(500);
Console::WriteLine(S"Object:{0}",state->ToString());
Object __pin *temp = __box(x);
unsigned char *ix = (unsigned char*)temp;
try
...{
Monitor::Enter(temp);
WriteMemoryContents(ix - 4,16);
}
catch(Exception *ex)
...{
Console::WriteLine(ex->ToString());
}
__finally
...{
//Monitor::Exit(temp);
}
}
static void WriteMemoryContents(unsigned char*startAddress,int nBytes)
...{
for (int i = 0; i < nBytes; i ++)
...{
if (i % 8 == 0)
Console::Write("Address {0:x}:",__box((int)(startAddress) + i));
if (startAddress[i] < 16)
Console::Write("0");
Console::Write("{0:x}",__box(startAddress[i]));
if (i % 4 == 3)
Console::Write(" ");
if (i % 8 == 7)
Console::WriteLine();
}
Console::WriteLine();
}
private:
static Int32 x = 5;
} ;
#pragma managed
int main()
... {
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl01"));
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl02"));
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl03"));
Console::ReadLine();
}
// Author by Yzl
# using < mscorlib.dll >
using namespace System;
using namespace System::Threading;
#pragma managed
__gc class CValueTypeDemo
... {
public:
static void ThreadProc(Object * state)
...{
Thread::Sleep(500);
Console::WriteLine(S"Object:{0}",state->ToString());
Object __pin *temp = __box(x);
unsigned char *ix = (unsigned char*)temp;
try
...{
Monitor::Enter(temp);
WriteMemoryContents(ix - 4,16);
}
catch(Exception *ex)
...{
Console::WriteLine(ex->ToString());
}
__finally
...{
//Monitor::Exit(temp);
}
}
static void WriteMemoryContents(unsigned char*startAddress,int nBytes)
...{
for (int i = 0; i < nBytes; i ++)
...{
if (i % 8 == 0)
Console::Write("Address {0:x}:",__box((int)(startAddress) + i));
if (startAddress[i] < 16)
Console::Write("0");
Console::Write("{0:x}",__box(startAddress[i]));
if (i % 4 == 3)
Console::Write(" ");
if (i % 8 == 7)
Console::WriteLine();
}
Console::WriteLine();
}
private:
static Int32 x = 5;
} ;
#pragma managed
int main()
... {
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl01"));
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl02"));
ThreadPool::QueueUserWorkItem(new WaitCallback(0,CValueTypeDemo::ThreadProc),new String("Yzl03"));
Console::ReadLine();
}
__pin 关键字防止无用单元收集器移动对象同时也可以让C++编译器允许我们将其强制转换为检查内存所需的非托管指针.
编译运行:
E:/>cl CValueTypeDemo.cpp /clr
E:/>CValueTypeDemo
Object:Yzl01
Address 4be39ac:03000000 0807b979
Address 4be39b4:05000000 00000000
Object:Yzl01
Address 4be39ac:03000000 0807b979
Address 4be39b4:05000000 00000000
Object:Yzl02
Address 4be5144:04000000 0807b979
Address 4be514c:05000000 00000000
Address 4be5144:04000000 0807b979
Address 4be514c:05000000 00000000
Object:Yzl03
Address 4be62bc:03000000 0807b979
Address 4be62c4:05000000 00000000
Address 4be62bc:03000000 0807b979
Address 4be62c4:05000000 00000000
exit
测试表明数据并未同步.第一次封箱产生的对象是4be39ac,它的同步对象索引块为03000000,值为05000000.
如果我们需要同步访问一个值类型,那么可以使用typeof(v)获取同步对象.
示例 -- 采用typeof同步数据
using
System;
using System.Threading;
public class TypeofDemo
... {
public static void Main(string[] args)
...{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl01");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl02");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl03");
Console.ReadLine();
}
private static void ThreadProc(object state)
...{
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
lock(typeof(int))
...{
x = AppDomain.GetCurrentThreadId();
Console.WriteLine("x={0}",x);
}
}
private static int x = 3;
}
using System.Threading;
public class TypeofDemo
... {
public static void Main(string[] args)
...{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl01");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl02");
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),"Yzl03");
Console.ReadLine();
}
private static void ThreadProc(object state)
...{
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
lock(typeof(int))
...{
x = AppDomain.GetCurrentThreadId();
Console.WriteLine("x={0}",x);
}
}
private static int x = 3;
}
编译运行:
E:/>csc TypeofDemo.cs
E:/>TypeofDemo
Object:Yzl01,Current Thread:2416
x=2416
Object:Yzl02,Current Thread:2416
x=2416
Object:Yzl03,Current Thread:2404
x=2404
exit
Object:Yzl01,Current Thread:2416
x=2416
Object:Yzl02,Current Thread:2416
x=2416
Object:Yzl03,Current Thread:2404
x=2404
exit
E:/>
记住,typeof(v)对于所有的v实例总是返回相同的对象.我们测试一下:
//
TypeofDemo.cs
// Author by Yzl
using System;
using System.Threading;
public class TypeofDemo
... {
public static void Main(string[] args)
...{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),1);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),2);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),3);
Console.ReadLine();
}
private static void ThreadProc(object state)
...{
lock(((int)state).GetType())
...{
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
}
}
}
// Author by Yzl
using System;
using System.Threading;
public class TypeofDemo
... {
public static void Main(string[] args)
...{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),1);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),2);
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc),3);
Console.ReadLine();
}
private static void ThreadProc(object state)
...{
lock(((int)state).GetType())
...{
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
Thread.Sleep(500);
Console.WriteLine("Object:{0},Current Thread:{1}",state,AppDomain.GetCurrentThreadId());
}
}
}
运行如下:
E:/>csc TypeofDemo.cs
E:/>csc TypeofDemo.cs
E:/>TypeofDemo
Object:1,Current Thread:1020
Object:1,Current Thread:1020
Object:2,Current Thread:2496
Object:2,Current Thread:2496
Object:3,Current Thread:1020
Object:3,Current Thread:1020
exit
Object:1,Current Thread:1020
Object:1,Current Thread:1020
Object:2,Current Thread:2496
Object:2,Current Thread:2496
Object:3,Current Thread:1020
Object:3,Current Thread:1020
exit
很明显各个线程先后执行完毕.如果将lock语句改为lock(state)我们观察下又会是什么样的结果:
E:/>TypeofDemo
Object:1,Current Thread:2444
Object:1,Current Thread:2444
Object:2,Current Thread:2508
Object:3,Current Thread:2512
Object:2,Current Thread:2508
Object:3,Current Thread:2512
exit
E:/>TypeofDemo
Object:1,Current Thread:2444
Object:1,Current Thread:2444
Object:2,Current Thread:2508
Object:3,Current Thread:2512
Object:2,Current Thread:2508
Object:3,Current Thread:2512
exit
线程执行并无顺序,2508号线程还没未执行完就被2512号线程抢去了.换句话说,这时的lock并没有起到同步对象的作用.
线程同步还涉及到死锁等现象,这里不再探讨.合理地应用锁才可能最大限度地预防数据破坏及产生死锁.
End.
--------------------------------------------------------------------------------
【版权声明】: 本文原创于厦门, 转载请注明作者并保持文章的完整, 谢谢!
【版权声明】: 本文原创于厦门, 转载请注明作者并保持文章的完整, 谢谢!
2007年03月02日 13:33:38