多线程同步与并发访问共享资源工具—Lock、Monitor、Mutex、Semaphore
“线程同步”的含义
当一个进程启动了多个线程时,如果需要控制这些线程的推进顺序(比如A线程必须等待B和C线程执行完毕之后才能继续执行),则称这些线程需要进行“线程同步(thread synchronization)”。
线程同步的道理虽然简单,但却是给多线程开发带来复杂性的根源之一。当线程同步不好时,有可能会出现一种特殊的情形——死锁(Dead Lock)。
“死锁”的含义
死锁表示系统进入了一个僵化状态,所有线程都没有执行完毕,但却谁也没法继续执行。究其根源,是因为“进程推进顺序不当”和“资源共享”。如例:
1)进程推进顺序不当造成死锁
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace JoinLeadToDeadlock
- {
- class Program
- {
- static Thread mainThread;
- static void Main(string[] args)
- {
- Console.WriteLine("主线程开始运行");
- mainThread = Thread.CurrentThread;
- Thread ta = new Thread(new ThreadStart(ThreadAMethod));
- ta.Start(); //线程A开始执行
- Console.WriteLine("主线程等待线程A结束……");
- ta.Join(); //等待线程A结束
- Console.WriteLine("主线程退出");
- }
- static void ThreadAMethod()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(Convert.ToString(i) + ": 线程A正在执行");
- Thread.Sleep(1000);
- }
- Console.WriteLine("线程A等待主线程退出……");
- mainThread.Join(); //等待主线程结束
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace JoinLeadToDeadlock
- {
- class Program
- {
- static Thread mainThread;
- static void Main(string[] args)
- {
- Console.WriteLine("主线程开始运行");
- mainThread = Thread.CurrentThread;
- Thread ta = new Thread(new ThreadStart(ThreadAMethod));
- ta.Start(); //线程A开始执行
- Console.WriteLine("主线程等待线程A结束……");
- ta.Join(); //等待线程A结束
- Console.WriteLine("主线程退出");
- }
- static void ThreadAMethod()
- {
- for (int i = 0; i < 10; i++)
- {
- Console.WriteLine(Convert.ToString(i) + ": 线程A正在执行");
- Thread.Sleep(1000);
- }
- Console.WriteLine("线程A等待主线程退出……");
- mainThread.Join(); //等待主线程结束
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace JoinLeadToDeadlock
{
class Program
{
static Thread mainThread;
static void Main(string[] args)
{
Console.WriteLine("主线程开始运行");
mainThread = Thread.CurrentThread; Thread ta = new Thread(new ThreadStart(ThreadAMethod));
ta.Start(); //线程A开始执行
Console.WriteLine("主线程等待线程A结束……");
ta.Join(); //等待线程A结束
Console.WriteLine("主线程退出");
} static void ThreadAMethod()
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine(Convert.ToString(i) + ": 线程A正在执行");
Thread.Sleep(1000);
}
Console.WriteLine("线程A等待主线程退出……");
mainThread.Join(); //等待主线程结束
}
}
}
在该例中,主线程mainThread先开始执行,然后启动线程ta,线程ta执行结束前又要等待mainThread线程执行结束,这样就出现了“交叉等待”的局面,必然死锁!
2)共享资源造成死锁
所谓“共享资源”,指的是多个线程可以同时访问的数据结构、文件等信息实体。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace SharedResourceLeadToDeadlock
- {
- class Program
- {
- //共享资源
- static SharedResource R1 = new SharedResource();
- static SharedResource R2 = new SharedResource();
- static void Main(string[] args)
- {
- Thread th1 = new Thread(UseSharedResource1);
- Thread th2 = new Thread(UseSharedResource2);
- th1.Start();
- th2.Start();
- //等待两线程运行结束
- th1.Join();
- th2.Join();
- }
- static void UseSharedResource1()
- {
- System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R1); //对R1加锁
- System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(1000);
- System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R2); //对R2加锁
- System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(1000);
- System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R2); //对R2解锁
- System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R1); //对R1解锁
- }
- static void UseSharedResource2()
- {
- System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R2); //对R2加锁
- System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(500);
- System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R1); //对R1加锁
- System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(500);
- System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R1); //对R1解锁
- System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R2); //对R2解锁
- }
- }
- class SharedResource
- {
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace SharedResourceLeadToDeadlock
- {
- class Program
- {
- //共享资源
- static SharedResource R1 = new SharedResource();
- static SharedResource R2 = new SharedResource();
- static void Main(string[] args)
- {
- Thread th1 = new Thread(UseSharedResource1);
- Thread th2 = new Thread(UseSharedResource2);
- th1.Start();
- th2.Start();
- //等待两线程运行结束
- th1.Join();
- th2.Join();
- }
- static void UseSharedResource1()
- {
- System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R1); //对R1加锁
- System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(1000);
- System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R2); //对R2加锁
- System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(1000);
- System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R2); //对R2解锁
- System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R1); //对R1解锁
- }
- static void UseSharedResource2()
- {
- System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R2); //对R2加锁
- System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(500);
- System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Monitor.Enter(R1); //对R1加锁
- System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
- Thread.Sleep(500);
- System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R1); //对R1解锁
- System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
- Monitor.Exit(R2); //对R2解锁
- }
- }
- class SharedResource
- {
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace SharedResourceLeadToDeadlock
{
class Program
{
//共享资源
static SharedResource R1 = new SharedResource();
static SharedResource R2 = new SharedResource(); static void Main(string[] args)
{
Thread th1 = new Thread(UseSharedResource1);
Thread th2 = new Thread(UseSharedResource2);
th1.Start();
th2.Start();
//等待两线程运行结束
th1.Join();
th2.Join();
} static void UseSharedResource1()
{
System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
Monitor.Enter(R1); //对R1加锁
System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
Monitor.Enter(R2); //对R2加锁
System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
Monitor.Exit(R2); //对R2解锁
System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
Monitor.Exit(R1); //对R1解锁
} static void UseSharedResource2()
{
System.Console.WriteLine("线程{0}申请使用资源R2", Thread.CurrentThread.ManagedThreadId);
Monitor.Enter(R2); //对R2加锁
System.Console.WriteLine("线程{0}独占使用资源R2", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
System.Console.WriteLine("线程{0}申请使用资源R1", Thread.CurrentThread.ManagedThreadId);
Monitor.Enter(R1); //对R1加锁
System.Console.WriteLine("线程{0}独占使用资源R1", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(500);
System.Console.WriteLine("线程{0}资源R1使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
Monitor.Exit(R1); //对R1解锁
System.Console.WriteLine("线程{0}资源R2使用完毕,放弃", Thread.CurrentThread.ManagedThreadId);
Monitor.Exit(R2); //对R2解锁
}
} class SharedResource
{
}
}
在该例中,线程th1执行时先申请使用R1,然后再申请使用R2,而线程th2执行时先申请R2,然后再申请R1,这样对于线程th1和th2,就会造成各自拥有一个对方需要的资源部释放,而又同时申请一个对方已经占有的资源,必然会造成死锁。
多线程数据存取错误
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace SharedResourceLeadToDataError
- {
- class Program
- {
- static void Main(string[] args)
- {
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i]=new Thread(increaseCount);
- ths[i].Start();
- }
- System.Console.ReadKey();
- }
- static void increaseCount()
- {
- Random ran = new Random();
- Thread.Sleep(ran.Next(100, 5000));
- int beginNum = SharedResource.Count;
- System.Console.WriteLine("线程 {0} 读到的起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNum );
- for (int i = 0; i < 10000; i++)
- {
- beginNum ++;
- }
- SharedResource.Count = beginNum;
- System.Console.WriteLine("线程 {0} 结束,SharedResource.Count={1}", Thread.CurrentThread.ManagedThreadId,SharedResource.Count);
- }
- }
- class SharedResource
- {
- public static int Count = 0;
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace SharedResourceLeadToDataError
- {
- class Program
- {
- static void Main(string[] args)
- {
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i]=new Thread(increaseCount);
- ths[i].Start();
- }
- System.Console.ReadKey();
- }
- static void increaseCount()
- {
- Random ran = new Random();
- Thread.Sleep(ran.Next(100, 5000));
- int beginNum = SharedResource.Count;
- System.Console.WriteLine("线程 {0} 读到的起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNum );
- for (int i = 0; i < 10000; i++)
- {
- beginNum ++;
- }
- SharedResource.Count = beginNum;
- System.Console.WriteLine("线程 {0} 结束,SharedResource.Count={1}", Thread.CurrentThread.ManagedThreadId,SharedResource.Count);
- }
- }
- class SharedResource
- {
- public static int Count = 0;
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace SharedResourceLeadToDataError
{
class Program
{
static void Main(string[] args)
{
Thread[] ths = new Thread[4];
for (int i = 0; i < 4; i++)
{
ths[i]=new Thread(increaseCount);
ths[i].Start();
}
System.Console.ReadKey();
} static void increaseCount()
{
Random ran = new Random();
Thread.Sleep(ran.Next(100, 5000));
int beginNum = SharedResource.Count;
System.Console.WriteLine("线程 {0} 读到的起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNum );
for (int i = 0; i < 10000; i++)
{
beginNum ++;
}
SharedResource.Count = beginNum;
System.Console.WriteLine("线程 {0} 结束,SharedResource.Count={1}", Thread.CurrentThread.ManagedThreadId,SharedResource.Count);
}
} class SharedResource
{
public static int Count = 0;
}
}
线程同步与并发访问控制手段
1、Monitor类
(1)使用方法
- Monitor对象的Enter方法可用于向共享资源申请一把“独占锁”。当一个线程拥有特定共享资源的独占锁时,尝试访问同一共享资源的其他线程只能等待。
- Monitor对象的Exit方法用于释放锁。
- 要注意:Enter与Exit方法必须严格配对,否则,有可能出现死锁情况。
- Monitor可以锁定单个对象,也可以锁定一个类型的静态字段或属性
2).Monitor.Enter(typeof(共享资源类型));
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- //展示用Monitor访问共享资源
- namespace UseMonitor1
- {
- class Program
- {
- static void Main(string[] args)
- {
- SharedResource obj = new SharedResource();
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i] = new Thread(increaseCount);
- ths[i].Start(obj);
- }
- System.Console.ReadKey();
- }
- static void increaseCount(Object obj)
- {
- //访问实例字段
- VisitDynamicField(obj);
- //访问静态字段
- VisitStaticField();
- }
- //访问静态字段
- private static void VisitStaticField()
- {
- //访问静态字段
- Monitor.Enter(typeof(SharedResource));
- int beginNumber = SharedResource.StaticCount;
- System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- SharedResource.StaticCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
- Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
- Monitor.Exit(typeof(SharedResource));
- }
- //访问实例字段
- private static void VisitDynamicField(Object obj)
- {
- Monitor.Enter(obj);
- int beginNumber = (obj as SharedResource).DynamicCount;
- System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- (obj as SharedResource).DynamicCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
- Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
- Monitor.Exit(obj);
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- public static int StaticCount = 0; //多线程共享的静态字段
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- //展示用Monitor访问共享资源
- namespace UseMonitor1
- {
- class Program
- {
- static void Main(string[] args)
- {
- SharedResource obj = new SharedResource();
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i] = new Thread(increaseCount);
- ths[i].Start(obj);
- }
- System.Console.ReadKey();
- }
- static void increaseCount(Object obj)
- {
- //访问实例字段
- VisitDynamicField(obj);
- //访问静态字段
- VisitStaticField();
- }
- //访问静态字段
- private static void VisitStaticField()
- {
- //访问静态字段
- Monitor.Enter(typeof(SharedResource));
- int beginNumber = SharedResource.StaticCount;
- System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- SharedResource.StaticCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
- Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
- Monitor.Exit(typeof(SharedResource));
- }
- //访问实例字段
- private static void VisitDynamicField(Object obj)
- {
- Monitor.Enter(obj);
- int beginNumber = (obj as SharedResource).DynamicCount;
- System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- (obj as SharedResource).DynamicCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
- Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
- Monitor.Exit(obj);
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- public static int StaticCount = 0; //多线程共享的静态字段
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; //展示用Monitor访问共享资源
namespace UseMonitor1
{
class Program
{
static void Main(string[] args)
{
SharedResource obj = new SharedResource(); Thread[] ths = new Thread[4];
for (int i = 0; i < 4; i++)
{
ths[i] = new Thread(increaseCount);
ths[i].Start(obj);
}
System.Console.ReadKey();
}
static void increaseCount(Object obj)
{
//访问实例字段
VisitDynamicField(obj);
//访问静态字段
VisitStaticField();
} //访问静态字段
private static void VisitStaticField()
{
//访问静态字段
Monitor.Enter(typeof(SharedResource)); int beginNumber = SharedResource.StaticCount;
System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
for (int i = 0; i < 10000; i++)
{
beginNumber++;
}
SharedResource.StaticCount = beginNumber;
System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount); Monitor.Exit(typeof(SharedResource));
} //访问实例字段
private static void VisitDynamicField(Object obj)
{
Monitor.Enter(obj); int beginNumber = (obj as SharedResource).DynamicCount;
System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
for (int i = 0; i < 10000; i++)
{
beginNumber++;
}
(obj as SharedResource).DynamicCount = beginNumber;
System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount); Monitor.Exit(obj);
}
}
//共享资源类
class SharedResource
{
public int DynamicCount = 0; //多线程共享的实例字段
public static int StaticCount = 0; //多线程共享的静态字段
}
}
Monitor类的使用模板:
Monitor.Enter(共享资源对象); //申请对象锁
//其他线程只能等待
//访问共享资源
//对共享资源的访问完成,释放对象锁,
//让其他线程有机会访问共享资源
(2)Monitor的特殊注意之处:
因此,不要将Monitor用于值类型!
(3) Monitor.Wait()和Monitor.Pulse()
Pulse(),PulseAll()向一个或多个等待线程发送信号。该信号通知等待线程锁定对象的状态已更改,并且锁的所有者准备释放该锁。等待线程被放置在对象的就绪队列中以便它可以最后接收对象锁。一旦线程拥有了锁,它就可以检查对象的新状态以查看是否达到所需状态。PulseAll与Pulse方法类似,不过它是向所有在阻塞队列中的进程发送通知信号,如果只有一个线程被阻塞,那么请使用Pulse方法。
注意:Pulse、PulseAll和Wait方法必须从同步的代码块内调用。
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseMonitor2
- {
- class Program
- {
- static void Main(string[] args)
- {
- //创建共享资源
- SharedResource obj = new SharedResource();
- //创建线程对象并启动
- Thread tha = new Thread(ThreadMethodA);
- Thread thb = new Thread(ThreadMethodB);
- tha.Start(obj);
- thb.Start(obj);
- //程序暂停
- System.Console.ReadKey();
- }
- static void ThreadMethodA(Object obj)
- {
- Monitor.Enter(obj);
- (obj as SharedResource).DynamicCount += 100;
- System.Console.WriteLine("线程A完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
- Monitor.Pulse(obj); //通知B线程进入准备队列
- Monitor.Exit(obj);
- }
- static void ThreadMethodB(Object obj)
- {
- Monitor.Enter(obj);
- //A线程还未工作,因为字段保持初始值0
- //如果注释掉此条件判断语句,则有可能会发生死锁
- if((obj as SharedResource).DynamicCount == 0)
- Monitor.Wait(obj);//将本线程阻塞,进入阻塞队列等待
- (obj as SharedResource).DynamicCount += 100;
- System.Console.WriteLine("线程B完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
- Monitor.Exit(obj);
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseMonitor2
- {
- class Program
- {
- static void Main(string[] args)
- {
- //创建共享资源
- SharedResource obj = new SharedResource();
- //创建线程对象并启动
- Thread tha = new Thread(ThreadMethodA);
- Thread thb = new Thread(ThreadMethodB);
- tha.Start(obj);
- thb.Start(obj);
- //程序暂停
- System.Console.ReadKey();
- }
- static void ThreadMethodA(Object obj)
- {
- Monitor.Enter(obj);
- (obj as SharedResource).DynamicCount += 100;
- System.Console.WriteLine("线程A完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
- Monitor.Pulse(obj); //通知B线程进入准备队列
- Monitor.Exit(obj);
- }
- static void ThreadMethodB(Object obj)
- {
- Monitor.Enter(obj);
- //A线程还未工作,因为字段保持初始值0
- //如果注释掉此条件判断语句,则有可能会发生死锁
- if((obj as SharedResource).DynamicCount == 0)
- Monitor.Wait(obj);//将本线程阻塞,进入阻塞队列等待
- (obj as SharedResource).DynamicCount += 100;
- System.Console.WriteLine("线程B完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
- Monitor.Exit(obj);
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace UseMonitor2
{
class Program
{
static void Main(string[] args)
{
//创建共享资源
SharedResource obj = new SharedResource();
//创建线程对象并启动
Thread tha = new Thread(ThreadMethodA);
Thread thb = new Thread(ThreadMethodB);
tha.Start(obj);
thb.Start(obj); //程序暂停
System.Console.ReadKey();
} static void ThreadMethodA(Object obj)
{
Monitor.Enter(obj);
(obj as SharedResource).DynamicCount += 100;
System.Console.WriteLine("线程A完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
Monitor.Pulse(obj); //通知B线程进入准备队列
Monitor.Exit(obj);
} static void ThreadMethodB(Object obj)
{
Monitor.Enter(obj);
//A线程还未工作,因为字段保持初始值0
//如果注释掉此条件判断语句,则有可能会发生死锁
if((obj as SharedResource).DynamicCount == 0)
Monitor.Wait(obj);//将本线程阻塞,进入阻塞队列等待
(obj as SharedResource).DynamicCount += 100;
System.Console.WriteLine("线程B完成工作,obj.DynamicCount={0}", (obj as SharedResource).DynamicCount);
Monitor.Exit(obj);
}
} //共享资源类
class SharedResource
{
public int DynamicCount = 0; //多线程共享的实例字段
}
}
例2:
- using System.Threading;
- public class Program
- {
- static object ball = new object();
- public static void Main()
- {
- Thread threadPing = new Thread( ThreadPingProc );
- Thread threadPong = new Thread( ThreadPongProc );
- threadPing.Start(); threadPong.Start();
- }
- static void ThreadPongProc()
- {
- System.Console.WriteLine("ThreadPong: Hello!");
- lock ( ball )
- for (int i = 0; i < 5; i++)
- {
- System.Console.WriteLine("ThreadPong: Pong ");
- Monitor.Pulse( ball );
- Monitor.Wait( ball );
- }
- System.Console.WriteLine("ThreadPong: Bye!");
- }
- static void ThreadPingProc()
- {
- System.Console.WriteLine("ThreadPing: Hello!");
- lock ( ball )
- for(int i=0; i< 5; i++)
- {
- System.Console.WriteLine("ThreadPing: Ping ");
- Monitor.Pulse( ball );
- Monitor.Wait( ball );
- }
- System.Console.WriteLine("ThreadPing: Bye!");
- }
- }
- using System.Threading;
- public class Program
- {
- static object ball = new object();
- public static void Main()
- {
- Thread threadPing = new Thread( ThreadPingProc );
- Thread threadPong = new Thread( ThreadPongProc );
- threadPing.Start(); threadPong.Start();
- }
- static void ThreadPongProc()
- {
- System.Console.WriteLine("ThreadPong: Hello!");
- lock ( ball )
- for (int i = 0; i < 5; i++)
- {
- System.Console.WriteLine("ThreadPong: Pong ");
- Monitor.Pulse( ball );
- Monitor.Wait( ball );
- }
- System.Console.WriteLine("ThreadPong: Bye!");
- }
- static void ThreadPingProc()
- {
- System.Console.WriteLine("ThreadPing: Hello!");
- lock ( ball )
- for(int i=0; i< 5; i++)
- {
- System.Console.WriteLine("ThreadPing: Ping ");
- Monitor.Pulse( ball );
- Monitor.Wait( ball );
- }
- System.Console.WriteLine("ThreadPing: Bye!");
- }
- }
using System.Threading;
public class Program
{
static object ball = new object();
public static void Main()
{
Thread threadPing = new Thread( ThreadPingProc );
Thread threadPong = new Thread( ThreadPongProc );
threadPing.Start(); threadPong.Start();
}
static void ThreadPongProc()
{
System.Console.WriteLine("ThreadPong: Hello!");
lock ( ball )
for (int i = 0; i < 5; i++)
{
System.Console.WriteLine("ThreadPong: Pong ");
Monitor.Pulse( ball );
Monitor.Wait( ball );
}
System.Console.WriteLine("ThreadPong: Bye!");
}
static void ThreadPingProc()
{
System.Console.WriteLine("ThreadPing: Hello!");
lock ( ball )
for(int i=0; i< 5; i++)
{
System.Console.WriteLine("ThreadPing: Ping ");
Monitor.Pulse( ball );
Monitor.Wait( ball );
}
System.Console.WriteLine("ThreadPing: Bye!");
}
}
- ThreadPing: Hello!
- ThreadPing: Ping
- ThreadPong: Hello!
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Bye!
- ThreadPing: Hello!
- ThreadPing: Ping
- ThreadPong: Hello!
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Ping
- ThreadPong: Pong
- ThreadPing: Bye!
ThreadPing: Hello!
ThreadPing: Ping
ThreadPong: Hello!
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Ping
ThreadPong: Pong
ThreadPing: Bye!
- //A线程执行的代码
- lock(obj)
- {
- //访问共享资源obj
- Monitor.Pulse(obj); //通知B 线程可以访问共享资源obj了
- }
- ---------------------------------------------------------------
- //B线程执行的代码
- lock(obj)
- {
- Monitor.Wait(obj); //等待A 线程完成
- //访问共享资源obj
- }
- //A线程执行的代码
- lock(obj)
- {
- //访问共享资源obj
- Monitor.Pulse(obj); //通知B 线程可以访问共享资源obj了
- }
- ---------------------------------------------------------------
- //B线程执行的代码
- lock(obj)
- {
- Monitor.Wait(obj); //等待A 线程完成
- //访问共享资源obj
- }
//A线程执行的代码
lock(obj)
{
//访问共享资源obj
Monitor.Pulse(obj); //通知B 线程可以访问共享资源obj了
}
---------------------------------------------------------------
//B线程执行的代码
lock(obj)
{
Monitor.Wait(obj); //等待A 线程完成
//访问共享资源obj
}
2、Lock关键字
//访问共享资源代码段
Monitor.Exit(obj);
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- //展示用Monitor访问共享资源
- namespace UseMonitor1
- {
- class Program
- {
- static void Main(string[] args)
- {
- SharedResource obj = new SharedResource();
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i] = new Thread(increaseCount);
- ths[i].Start(obj);
- }
- System.Console.ReadKey();
- }
- static void increaseCount(Object obj)
- {
- //访问实例字段
- VisitDynamicField(obj);
- //访问静态字段
- VisitStaticField();
- }
- //访问静态字段
- private static void VisitStaticField()
- {
- //访问静态字段
- lock (typeof(SharedResource))
- {
- int beginNumber = SharedResource.StaticCount;
- System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- SharedResource.StaticCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
- Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
- }
- }
- //访问实例字段
- private static void VisitDynamicField(Object obj)
- {
- lock (obj)
- {
- int beginNumber = (obj as SharedResource).DynamicCount;
- System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- (obj as SharedResource).DynamicCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
- Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
- }
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- public static int StaticCount = 0; //多线程共享的静态字段
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- //展示用Monitor访问共享资源
- namespace UseMonitor1
- {
- class Program
- {
- static void Main(string[] args)
- {
- SharedResource obj = new SharedResource();
- Thread[] ths = new Thread[4];
- for (int i = 0; i < 4; i++)
- {
- ths[i] = new Thread(increaseCount);
- ths[i].Start(obj);
- }
- System.Console.ReadKey();
- }
- static void increaseCount(Object obj)
- {
- //访问实例字段
- VisitDynamicField(obj);
- //访问静态字段
- VisitStaticField();
- }
- //访问静态字段
- private static void VisitStaticField()
- {
- //访问静态字段
- lock (typeof(SharedResource))
- {
- int beginNumber = SharedResource.StaticCount;
- System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- SharedResource.StaticCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
- Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
- }
- }
- //访问实例字段
- private static void VisitDynamicField(Object obj)
- {
- lock (obj)
- {
- int beginNumber = (obj as SharedResource).DynamicCount;
- System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
- for (int i = 0; i < 10000; i++)
- {
- beginNumber++;
- }
- (obj as SharedResource).DynamicCount = beginNumber;
- System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
- Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
- }
- }
- }
- //共享资源类
- class SharedResource
- {
- public int DynamicCount = 0; //多线程共享的实例字段
- public static int StaticCount = 0; //多线程共享的静态字段
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; //展示用Monitor访问共享资源
namespace UseMonitor1
{
class Program
{
static void Main(string[] args)
{
SharedResource obj = new SharedResource(); Thread[] ths = new Thread[4];
for (int i = 0; i < 4; i++)
{
ths[i] = new Thread(increaseCount);
ths[i].Start(obj);
}
System.Console.ReadKey();
}
static void increaseCount(Object obj)
{
//访问实例字段
VisitDynamicField(obj);
//访问静态字段
VisitStaticField();
} //访问静态字段
private static void VisitStaticField()
{
//访问静态字段
lock (typeof(SharedResource))
{
int beginNumber = SharedResource.StaticCount;
System.Console.WriteLine("线程 {0} 读到的StaticCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
for (int i = 0; i < 10000; i++)
{
beginNumber++;
}
SharedResource.StaticCount = beginNumber;
System.Console.WriteLine("线程 {0} 结束, SharedResource.StaticCount={1}",
Thread.CurrentThread.ManagedThreadId, SharedResource.StaticCount);
}
} //访问实例字段
private static void VisitDynamicField(Object obj)
{
lock (obj)
{
int beginNumber = (obj as SharedResource).DynamicCount;
System.Console.WriteLine("线程 {0} 读到的DynamicCount起始值为 {1} ", Thread.CurrentThread.ManagedThreadId, beginNumber);
for (int i = 0; i < 10000; i++)
{
beginNumber++;
}
(obj as SharedResource).DynamicCount = beginNumber;
System.Console.WriteLine("线程 {0} 结束,Obj.DynamicCount={1}",
Thread.CurrentThread.ManagedThreadId, (obj as SharedResource).DynamicCount);
}
}
}
//共享资源类
class SharedResource
{
public int DynamicCount = 0; //多线程共享的实例字段
public static int StaticCount = 0; //多线程共享的静态字段
}
}
3、自旋锁SpinLock
- public class MyType
- {
- //创建自旋锁对象
- private SpinLock _spinLock = new SpinLock();
- //将被多线程执行的代码,
- //由于使用了自旋锁,可以保证被“锁定”代码一次只会被一个线程执行
- public void DoWork()
- {
- bool lockTaken = false;
- try
- {
- _spinLock.Enter(ref lockTaken); //申请获取“锁”
- // 获得了锁,在此书写工作代码,这些工作代码不会同时被两个线程执行
- }
- finally
- {
- //工作完毕,或者发生异常时,检查一下当前线程是否占有了锁
- //如果占有了锁,释放它,以避免出现死锁的情况。
- if (lockTaken) _spinLock.Exit();
- }
- }
- }
- public class MyType
- {
- //创建自旋锁对象
- private SpinLock _spinLock = new SpinLock();
- //将被多线程执行的代码,
- //由于使用了自旋锁,可以保证被“锁定”代码一次只会被一个线程执行
- public void DoWork()
- {
- bool lockTaken = false;
- try
- {
- _spinLock.Enter(ref lockTaken); //申请获取“锁”
- // 获得了锁,在此书写工作代码,这些工作代码不会同时被两个线程执行
- }
- finally
- {
- //工作完毕,或者发生异常时,检查一下当前线程是否占有了锁
- //如果占有了锁,释放它,以避免出现死锁的情况。
- if (lockTaken) _spinLock.Exit();
- }
- }
- }
public class MyType
{
//创建自旋锁对象
private SpinLock _spinLock = new SpinLock();
//将被多线程执行的代码,
//由于使用了自旋锁,可以保证被“锁定”代码一次只会被一个线程执行
public void DoWork()
{
bool lockTaken = false;
try
{
_spinLock.Enter(ref lockTaken); //申请获取“锁”
// 获得了锁,在此书写工作代码,这些工作代码不会同时被两个线程执行
}
finally
{
//工作完毕,或者发生异常时,检查一下当前线程是否占有了锁
//如果占有了锁,释放它,以避免出现死锁的情况。
if (lockTaken) _spinLock.Exit();
}
}
}
4、实现原子操作——Interlocked类
- 将实例变量中的值加载到寄存器中。
- 增加或减少该值。
- 在实例变量中存储该值。
如果不使用 Increment 和 Decrement,线程会在执行完前两个步骤后被抢先。 然后由另一个线程执行所有三个步骤。 当第一个线程重新开始执行时,它覆盖实例变量中的值,造成第二个线程执行增减操作的结果丢失。
- // Interlocked.cs
- // Interlocked示例
- using System;
- using System.Threading;
- class Test
- {
- private long bufferEmpty = 0;
- private string buffer = null;
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- Thread t1 = new Thread(new ThreadStart(Producer));
- t1.Name = "生产者线程";
- t1.Start();
- Thread t2 = new Thread(new ThreadStart(Consumer));
- t2.Name = "消费者线程";
- t2.Start();
- // 等待两个线程结束
- t1.Join();
- t2.Join();
- }
- // 生产者方法
- public void Producer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- try
- {
- for (int j = 0; j < 16; ++j)
- {
- // 等待共享缓冲区为空
- while (Interlocked.Read(ref bufferEmpty) != 0)
- Thread.Sleep(100);
- // 构造共享缓冲区
- Random r = new Random();
- int bufSize = r.Next() % 64;
- char[] s = new char[bufSize];
- for (int i = 0; i < bufSize; ++i)
- {
- s[i] = (char)((int)'A' + r.Next() % 26);
- }
- buffer = new string(s);
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer);
- // 互锁加一,成为1,标志共享缓冲区已满
- Interlocked.Increment(ref bufferEmpty);
- // 休眠,将时间片让给消费者
- Thread.Sleep(10);
- }
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- }
- }
- // 消费者方法
- public void Consumer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- try
- {
- for (int j = 0; j < 16; ++j)
- {
- while (Interlocked.Read(ref bufferEmpty) == 0)
- Thread.Sleep(100);
- // 打印共享缓冲区
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer);
- // 互锁减一,成为0,标志共享缓冲区已空
- Interlocked.Decrement(ref bufferEmpty);
- // 休眠,将时间片让给生产者
- Thread.Sleep(10);
- }
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- }
- }
- }
- // Interlocked.cs
- // Interlocked示例
- using System;
- using System.Threading;
- class Test
- {
- private long bufferEmpty = 0;
- private string buffer = null;
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- Thread t1 = new Thread(new ThreadStart(Producer));
- t1.Name = "生产者线程";
- t1.Start();
- Thread t2 = new Thread(new ThreadStart(Consumer));
- t2.Name = "消费者线程";
- t2.Start();
- // 等待两个线程结束
- t1.Join();
- t2.Join();
- }
- // 生产者方法
- public void Producer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- try
- {
- for (int j = 0; j < 16; ++j)
- {
- // 等待共享缓冲区为空
- while (Interlocked.Read(ref bufferEmpty) != 0)
- Thread.Sleep(100);
- // 构造共享缓冲区
- Random r = new Random();
- int bufSize = r.Next() % 64;
- char[] s = new char[bufSize];
- for (int i = 0; i < bufSize; ++i)
- {
- s[i] = (char)((int)'A' + r.Next() % 26);
- }
- buffer = new string(s);
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer);
- // 互锁加一,成为1,标志共享缓冲区已满
- Interlocked.Increment(ref bufferEmpty);
- // 休眠,将时间片让给消费者
- Thread.Sleep(10);
- }
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- }
- }
- // 消费者方法
- public void Consumer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- try
- {
- for (int j = 0; j < 16; ++j)
- {
- while (Interlocked.Read(ref bufferEmpty) == 0)
- Thread.Sleep(100);
- // 打印共享缓冲区
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer);
- // 互锁减一,成为0,标志共享缓冲区已空
- Interlocked.Decrement(ref bufferEmpty);
- // 休眠,将时间片让给生产者
- Thread.Sleep(10);
- }
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- }
- }
- }
// Interlocked.cs
// Interlocked示例 using System;
using System.Threading; class Test
{
private long bufferEmpty = 0;
private string buffer = null; static void Main()
{
Test t = new Test();
// 进行测试
t.Go();
} public void Go()
{
Thread t1 = new Thread(new ThreadStart(Producer));
t1.Name = "生产者线程";
t1.Start(); Thread t2 = new Thread(new ThreadStart(Consumer));
t2.Name = "消费者线程";
t2.Start(); // 等待两个线程结束
t1.Join();
t2.Join();
} // 生产者方法
public void Producer()
{
Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name); try
{
for (int j = 0; j < 16; ++j)
{
// 等待共享缓冲区为空
while (Interlocked.Read(ref bufferEmpty) != 0)
Thread.Sleep(100); // 构造共享缓冲区
Random r = new Random();
int bufSize = r.Next() % 64;
char[] s = new char[bufSize];
for (int i = 0; i < bufSize; ++i)
{
s[i] = (char)((int)'A' + r.Next() % 26);
}
buffer = new string(s); Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer); // 互锁加一,成为1,标志共享缓冲区已满
Interlocked.Increment(ref bufferEmpty); // 休眠,将时间片让给消费者
Thread.Sleep(10);
} Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
}
catch (System.Threading.ThreadInterruptedException)
{
Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
}
} // 消费者方法
public void Consumer()
{
Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name); try
{
for (int j = 0; j < 16; ++j)
{
while (Interlocked.Read(ref bufferEmpty) == 0)
Thread.Sleep(100); // 打印共享缓冲区
Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, buffer); // 互锁减一,成为0,标志共享缓冲区已空
Interlocked.Decrement(ref bufferEmpty); // 休眠,将时间片让给生产者
Thread.Sleep(10);
} Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
}
catch (System.Threading.ThreadInterruptedException)
{
Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
}
}
}
5、Mutex类
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseATM
- {
- class Program
- {
- static ATM OneATM=new ATM(); //共享资源
- static void Main(string[] args)
- {
- //向公共帐号存款2万
- Console.Write("输入公司公共帐户的金额:");
- int PublicAcountMoney =Convert.ToInt32(Console.ReadLine());
- OneATM.Deposit(PublicAcountMoney);
- Console.Write("输入ATM中的现金额:");
- int ATMLeftMoney = Convert.ToInt32(Console.ReadLine());
- OneATM.SetATMLeftMoney(ATMLeftMoney);
- System.Console.WriteLine("\n敲任意键从公共帐户中取钱,ESC键退出……\n");
- while (System.Console.ReadKey(true).Key !=ConsoleKey.Escape)
- {
- System.Console.WriteLine("");
- Thread One = new Thread(WithDrawMoney);
- Thread Two = new Thread(WithDrawMoney);
- Thread Three = new Thread(WithDrawMoney);
- //随机生成一个要提款的数额,最少100元,最高5000元
- Random ran = new Random();
- One.Start(ran.Next(100, 5000));
- Two.Start(ran.Next(100, 5000));
- Three.Start(ran.Next(100, 5000));
- //等三人取完钱
- One.Join();
- Two.Join();
- Three.Join();
- System.Console.WriteLine("公共账号剩余{0}元,ATM中可提现金:{1}", OneATM.QueryPublicAccount(),OneATM.QueryATMLeftAccount());
- }
- }
- //线程函数
- static void WithDrawMoney(object amount)
- {
- switch(OneATM.WithDraw((int)amount))
- {
- case WithDrawState.Succeed:
- System.Console.WriteLine("成功取出{0}元。",amount );
- break;
- case WithDrawState.ATMHasNotEnoughCash:
- System.Console.WriteLine("ATM中现金不足,无法支取{0}元。", amount);
- break ;
- case WithDrawState.AccountHasNotEnoughMoney:
- System.Console.WriteLine("帐户中没钱了!无法取出{0}元",amount);
- break ;
- }
- }
- }
- //自助取款机
- class ATM
- {
- private int PublicAcountLeftMoney;//帐户剩余的钱
- private int ATMLeftMoney;//提款机剩余的钱
- //同步信息号量
- private Mutex m = new Mutex();
- //取钱
- public WithDrawState WithDraw(int amount)
- {
- m.WaitOne();
- //公共帐号钱不够
- if (PublicAcountLeftMoney < amount)
- {
- m.ReleaseMutex();
- return WithDrawState.AccountHasNotEnoughMoney;
- }
- //ATM现金不够
- if (ATMLeftMoney < amount)
- {
- m.ReleaseMutex();
- return WithDrawState.ATMHasNotEnoughCash;
- }
- //用户可以提取现金
- ATMLeftMoney -= amount;
- PublicAcountLeftMoney -= amount;
- m.ReleaseMutex();
- return WithDrawState.Succeed;
- }
- //存钱
- public void Deposit(int amount)
- {
- m.WaitOne();
- PublicAcountLeftMoney += amount;
- m.ReleaseMutex();
- }
- /// <summary>
- /// 设置ATM的现金金额
- /// </summary>
- /// <param name="amount"></param>
- public void SetATMLeftMoney(int amount)
- {
- Interlocked.Exchange(ref ATMLeftMoney, amount);
- }
- //获取还剩余多少钱
- public int QueryPublicAccount()
- {
- return PublicAcountLeftMoney;
- }
- /// <summary>
- /// 查询ATM剩余多少钱
- /// </summary>
- /// <returns></returns>
- public int QueryATMLeftAccount()
- {
- return ATMLeftMoney;
- }
- }
- //取款状态
- public enum WithDrawState
- {
- Succeed, //取钱成功
- AccountHasNotEnoughMoney, //账号中没钱了
- ATMHasNotEnoughCash //ATM中没有足够的现金
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseATM
- {
- class Program
- {
- static ATM OneATM=new ATM(); //共享资源
- static void Main(string[] args)
- {
- //向公共帐号存款2万
- Console.Write("输入公司公共帐户的金额:");
- int PublicAcountMoney =Convert.ToInt32(Console.ReadLine());
- OneATM.Deposit(PublicAcountMoney);
- Console.Write("输入ATM中的现金额:");
- int ATMLeftMoney = Convert.ToInt32(Console.ReadLine());
- OneATM.SetATMLeftMoney(ATMLeftMoney);
- System.Console.WriteLine("\n敲任意键从公共帐户中取钱,ESC键退出……\n");
- while (System.Console.ReadKey(true).Key !=ConsoleKey.Escape)
- {
- System.Console.WriteLine("");
- Thread One = new Thread(WithDrawMoney);
- Thread Two = new Thread(WithDrawMoney);
- Thread Three = new Thread(WithDrawMoney);
- //随机生成一个要提款的数额,最少100元,最高5000元
- Random ran = new Random();
- One.Start(ran.Next(100, 5000));
- Two.Start(ran.Next(100, 5000));
- Three.Start(ran.Next(100, 5000));
- //等三人取完钱
- One.Join();
- Two.Join();
- Three.Join();
- System.Console.WriteLine("公共账号剩余{0}元,ATM中可提现金:{1}", OneATM.QueryPublicAccount(),OneATM.QueryATMLeftAccount());
- }
- }
- //线程函数
- static void WithDrawMoney(object amount)
- {
- switch(OneATM.WithDraw((int)amount))
- {
- case WithDrawState.Succeed:
- System.Console.WriteLine("成功取出{0}元。",amount );
- break;
- case WithDrawState.ATMHasNotEnoughCash:
- System.Console.WriteLine("ATM中现金不足,无法支取{0}元。", amount);
- break ;
- case WithDrawState.AccountHasNotEnoughMoney:
- System.Console.WriteLine("帐户中没钱了!无法取出{0}元",amount);
- break ;
- }
- }
- }
- //自助取款机
- class ATM
- {
- private int PublicAcountLeftMoney;//帐户剩余的钱
- private int ATMLeftMoney;//提款机剩余的钱
- //同步信息号量
- private Mutex m = new Mutex();
- //取钱
- public WithDrawState WithDraw(int amount)
- {
- m.WaitOne();
- //公共帐号钱不够
- if (PublicAcountLeftMoney < amount)
- {
- m.ReleaseMutex();
- return WithDrawState.AccountHasNotEnoughMoney;
- }
- //ATM现金不够
- if (ATMLeftMoney < amount)
- {
- m.ReleaseMutex();
- return WithDrawState.ATMHasNotEnoughCash;
- }
- //用户可以提取现金
- ATMLeftMoney -= amount;
- PublicAcountLeftMoney -= amount;
- m.ReleaseMutex();
- return WithDrawState.Succeed;
- }
- //存钱
- public void Deposit(int amount)
- {
- m.WaitOne();
- PublicAcountLeftMoney += amount;
- m.ReleaseMutex();
- }
- /// <summary>
- /// 设置ATM的现金金额
- /// </summary>
- /// <param name="amount"></param>
- public void SetATMLeftMoney(int amount)
- {
- Interlocked.Exchange(ref ATMLeftMoney, amount);
- }
- //获取还剩余多少钱
- public int QueryPublicAccount()
- {
- return PublicAcountLeftMoney;
- }
- /// <summary>
- /// 查询ATM剩余多少钱
- /// </summary>
- /// <returns></returns>
- public int QueryATMLeftAccount()
- {
- return ATMLeftMoney;
- }
- }
- //取款状态
- public enum WithDrawState
- {
- Succeed, //取钱成功
- AccountHasNotEnoughMoney, //账号中没钱了
- ATMHasNotEnoughCash //ATM中没有足够的现金
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace UseATM
{
class Program
{
static ATM OneATM=new ATM(); //共享资源
static void Main(string[] args)
{
//向公共帐号存款2万 Console.Write("输入公司公共帐户的金额:");
int PublicAcountMoney =Convert.ToInt32(Console.ReadLine());
OneATM.Deposit(PublicAcountMoney); Console.Write("输入ATM中的现金额:");
int ATMLeftMoney = Convert.ToInt32(Console.ReadLine());
OneATM.SetATMLeftMoney(ATMLeftMoney); System.Console.WriteLine("\n敲任意键从公共帐户中取钱,ESC键退出……\n"); while (System.Console.ReadKey(true).Key !=ConsoleKey.Escape)
{
System.Console.WriteLine("");
Thread One = new Thread(WithDrawMoney);
Thread Two = new Thread(WithDrawMoney);
Thread Three = new Thread(WithDrawMoney); //随机生成一个要提款的数额,最少100元,最高5000元
Random ran = new Random();
One.Start(ran.Next(100, 5000));
Two.Start(ran.Next(100, 5000));
Three.Start(ran.Next(100, 5000)); //等三人取完钱
One.Join();
Two.Join();
Three.Join(); System.Console.WriteLine("公共账号剩余{0}元,ATM中可提现金:{1}", OneATM.QueryPublicAccount(),OneATM.QueryATMLeftAccount());
}
} //线程函数
static void WithDrawMoney(object amount)
{
switch(OneATM.WithDraw((int)amount))
{
case WithDrawState.Succeed:
System.Console.WriteLine("成功取出{0}元。",amount );
break;
case WithDrawState.ATMHasNotEnoughCash:
System.Console.WriteLine("ATM中现金不足,无法支取{0}元。", amount);
break ;
case WithDrawState.AccountHasNotEnoughMoney:
System.Console.WriteLine("帐户中没钱了!无法取出{0}元",amount);
break ;
}
}
} //自助取款机
class ATM
{
private int PublicAcountLeftMoney;//帐户剩余的钱
private int ATMLeftMoney;//提款机剩余的钱 //同步信息号量
private Mutex m = new Mutex(); //取钱
public WithDrawState WithDraw(int amount)
{
m.WaitOne();
//公共帐号钱不够
if (PublicAcountLeftMoney < amount)
{
m.ReleaseMutex();
return WithDrawState.AccountHasNotEnoughMoney;
}
//ATM现金不够
if (ATMLeftMoney < amount)
{
m.ReleaseMutex();
return WithDrawState.ATMHasNotEnoughCash;
}
//用户可以提取现金
ATMLeftMoney -= amount;
PublicAcountLeftMoney -= amount;
m.ReleaseMutex();
return WithDrawState.Succeed;
}
//存钱
public void Deposit(int amount)
{
m.WaitOne();
PublicAcountLeftMoney += amount;
m.ReleaseMutex();
} /// <summary>
/// 设置ATM的现金金额
/// </summary>
/// <param name="amount"></param>
public void SetATMLeftMoney(int amount)
{
Interlocked.Exchange(ref ATMLeftMoney, amount);
}
//获取还剩余多少钱
public int QueryPublicAccount()
{
return PublicAcountLeftMoney;
} /// <summary>
/// 查询ATM剩余多少钱
/// </summary>
/// <returns></returns>
public int QueryATMLeftAccount()
{
return ATMLeftMoney;
}
}
//取款状态
public enum WithDrawState
{
Succeed, //取钱成功
AccountHasNotEnoughMoney, //账号中没钱了
ATMHasNotEnoughCash //ATM中没有足够的现金
}
}
可能的运行结果:
- 输入公司公共帐户的金额:200000
- 输入ATM中的现金额:6000000
- 敲任意键从公共帐户中取钱,ESC键退出……
- 成功取出1249元。
- 成功取出643元。
- 成功取出4958元。
- 公共账号剩余193150元,ATM中可提现金:5993150
- 成功取出1168元。
- 成功取出3650元。
- 成功取出2707元。
- 公共账号剩余185625元,ATM中可提现金:5985625
- 成功取出3866元。
- 成功取出402元。
- 成功取出2397元。
- 公共账号剩余178960元,ATM中可提现金:5978960
- 成功取出4485元。
- 成功取出1701元。
- 成功取出3354元。
- 公共账号剩余169420元,ATM中可提现金:5969420
- 输入公司公共帐户的金额:200000
- 输入ATM中的现金额:6000000
- 敲任意键从公共帐户中取钱,ESC键退出……
- 成功取出1249元。
- 成功取出643元。
- 成功取出4958元。
- 公共账号剩余193150元,ATM中可提现金:5993150
- 成功取出1168元。
- 成功取出3650元。
- 成功取出2707元。
- 公共账号剩余185625元,ATM中可提现金:5985625
- 成功取出3866元。
- 成功取出402元。
- 成功取出2397元。
- 公共账号剩余178960元,ATM中可提现金:5978960
- 成功取出4485元。
- 成功取出1701元。
- 成功取出3354元。
- 公共账号剩余169420元,ATM中可提现金:5969420
输入公司公共帐户的金额:200000
输入ATM中的现金额:6000000 敲任意键从公共帐户中取钱,ESC键退出…… 成功取出1249元。
成功取出643元。
成功取出4958元。
公共账号剩余193150元,ATM中可提现金:5993150 成功取出1168元。
成功取出3650元。
成功取出2707元。
公共账号剩余185625元,ATM中可提现金:5985625 成功取出3866元。
成功取出402元。
成功取出2397元。
公共账号剩余178960元,ATM中可提现金:5978960 成功取出4485元。
成功取出1701元。
成功取出3354元。
公共账号剩余169420元,ATM中可提现金:5969420
Mustex与Monitor有一个很大的区别:
- // Mutex1.cs
- // Mutex1示例
- using System;
- using System.IO;
- using System.Threading;
- using System.Diagnostics;
- class Test
- {
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- // 创建并启动线程
- Thread t1 = new Thread(new ThreadStart(Producer));
- t1.Name = "生产者线程";
- t1.Start();
- // 等待线程结束
- t1.Join();
- Console.WriteLine("按Enter键退出...");
- Console.Read();
- }
- // 生产者方法
- public void Producer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- // 创建互斥体
- Mutex mutex = new Mutex(false, "CSharp_Mutex_test");
- // 启动消费者进程
- Process.Start("Mutex2.exe");
- for (int j = 0; j < 16; ++j)
- {
- try
- {
- // 进入互斥体
- mutex.WaitOne();
- FileStream fs = new FileStream(@"d:\text.txt", FileMode.OpenOrCreate, FileAccess.Write);
- StreamWriter sw = new StreamWriter(fs);
- // 构造字符串
- Random r = new Random();
- int bufSize = r.Next() % 64;
- char[] s = new char[bufSize];
- for (int i = 0; i < bufSize; ++i)
- {
- s[i] = (char)((int)'A' + r.Next() % 26);
- }
- string str = new string(s);
- // 将字符串写入文件
- sw.WriteLine(str);
- sw.Close();
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, str);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- break;
- }
- finally
- {
- // 退出互斥体
- mutex.ReleaseMutex();
- }
- // 休眠,将时间片让给消费者
- Thread.Sleep(1000);
- }
- // 关闭互斥体
- mutex.Close();
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- }
- // Mutex1.cs
- // Mutex1示例
- using System;
- using System.IO;
- using System.Threading;
- using System.Diagnostics;
- class Test
- {
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- // 创建并启动线程
- Thread t1 = new Thread(new ThreadStart(Producer));
- t1.Name = "生产者线程";
- t1.Start();
- // 等待线程结束
- t1.Join();
- Console.WriteLine("按Enter键退出...");
- Console.Read();
- }
- // 生产者方法
- public void Producer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- // 创建互斥体
- Mutex mutex = new Mutex(false, "CSharp_Mutex_test");
- // 启动消费者进程
- Process.Start("Mutex2.exe");
- for (int j = 0; j < 16; ++j)
- {
- try
- {
- // 进入互斥体
- mutex.WaitOne();
- FileStream fs = new FileStream(@"d:\text.txt", FileMode.OpenOrCreate, FileAccess.Write);
- StreamWriter sw = new StreamWriter(fs);
- // 构造字符串
- Random r = new Random();
- int bufSize = r.Next() % 64;
- char[] s = new char[bufSize];
- for (int i = 0; i < bufSize; ++i)
- {
- s[i] = (char)((int)'A' + r.Next() % 26);
- }
- string str = new string(s);
- // 将字符串写入文件
- sw.WriteLine(str);
- sw.Close();
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, str);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- break;
- }
- finally
- {
- // 退出互斥体
- mutex.ReleaseMutex();
- }
- // 休眠,将时间片让给消费者
- Thread.Sleep(1000);
- }
- // 关闭互斥体
- mutex.Close();
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- }
// Mutex1.cs
// Mutex1示例 using System;
using System.IO;
using System.Threading;
using System.Diagnostics; class Test
{
static void Main()
{
Test t = new Test();
// 进行测试
t.Go();
} public void Go()
{
// 创建并启动线程
Thread t1 = new Thread(new ThreadStart(Producer));
t1.Name = "生产者线程";
t1.Start(); // 等待线程结束
t1.Join(); Console.WriteLine("按Enter键退出...");
Console.Read();
} // 生产者方法
public void Producer()
{
Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name); // 创建互斥体
Mutex mutex = new Mutex(false, "CSharp_Mutex_test"); // 启动消费者进程
Process.Start("Mutex2.exe"); for (int j = 0; j < 16; ++j)
{
try
{
// 进入互斥体
mutex.WaitOne(); FileStream fs = new FileStream(@"d:\text.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
// 构造字符串
Random r = new Random();
int bufSize = r.Next() % 64;
char[] s = new char[bufSize];
for (int i = 0; i < bufSize; ++i)
{
s[i] = (char)((int)'A' + r.Next() % 26);
}
string str = new string(s);
// 将字符串写入文件
sw.WriteLine(str);
sw.Close(); Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, str);
}
catch (System.Threading.ThreadInterruptedException)
{
Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
break;
}
finally
{
// 退出互斥体
mutex.ReleaseMutex();
} // 休眠,将时间片让给消费者
Thread.Sleep(1000);
} // 关闭互斥体
mutex.Close();
Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
}
}
消费者线程所在应用程序代码:
- // Mutex2.cs
- // Mutex2示例
- using System;
- using System.IO;
- using System.Threading;
- class Test
- {
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- // 创建并启动线程
- Thread t2 = new Thread(new ThreadStart(Consumer));
- t2.Name = "消费者线程";
- t2.Start();
- // 等待线程结束
- t2.Join();
- Console.WriteLine("按Enter键退出...");
- Console.Read();
- }
- // 消费者方法
- public void Consumer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- // 创建互斥体
- Mutex mutex = new Mutex(false, "CSharp_Mutex_test");
- for (int j = 0; j < 16; ++j)
- {
- try
- {
- // 进入互斥体
- mutex.WaitOne();
- StreamReader sr = new StreamReader(@"d:\text.txt");
- string s = sr.ReadLine();
- sr.Close();
- // 显示字符串的值
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, s);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- break;
- }
- finally
- {
- // 退出互斥体
- mutex.ReleaseMutex();
- }
- // 休眠,将时间片让给消费者
- Thread.Sleep(1000);
- }
- // 关闭互斥体
- mutex.Close();
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- }
- // Mutex2.cs
- // Mutex2示例
- using System;
- using System.IO;
- using System.Threading;
- class Test
- {
- static void Main()
- {
- Test t = new Test();
- // 进行测试
- t.Go();
- }
- public void Go()
- {
- // 创建并启动线程
- Thread t2 = new Thread(new ThreadStart(Consumer));
- t2.Name = "消费者线程";
- t2.Start();
- // 等待线程结束
- t2.Join();
- Console.WriteLine("按Enter键退出...");
- Console.Read();
- }
- // 消费者方法
- public void Consumer()
- {
- Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name);
- // 创建互斥体
- Mutex mutex = new Mutex(false, "CSharp_Mutex_test");
- for (int j = 0; j < 16; ++j)
- {
- try
- {
- // 进入互斥体
- mutex.WaitOne();
- StreamReader sr = new StreamReader(@"d:\text.txt");
- string s = sr.ReadLine();
- sr.Close();
- // 显示字符串的值
- Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, s);
- }
- catch (System.Threading.ThreadInterruptedException)
- {
- Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
- break;
- }
- finally
- {
- // 退出互斥体
- mutex.ReleaseMutex();
- }
- // 休眠,将时间片让给消费者
- Thread.Sleep(1000);
- }
- // 关闭互斥体
- mutex.Close();
- Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
- }
- }
// Mutex2.cs
// Mutex2示例 using System;
using System.IO;
using System.Threading; class Test
{
static void Main()
{
Test t = new Test();
// 进行测试
t.Go();
} public void Go()
{
// 创建并启动线程
Thread t2 = new Thread(new ThreadStart(Consumer));
t2.Name = "消费者线程";
t2.Start(); // 等待线程结束
t2.Join(); Console.WriteLine("按Enter键退出...");
Console.Read();
} // 消费者方法
public void Consumer()
{
Console.WriteLine("{0}:开始执行", Thread.CurrentThread.Name); // 创建互斥体
Mutex mutex = new Mutex(false, "CSharp_Mutex_test"); for (int j = 0; j < 16; ++j)
{
try
{
// 进入互斥体
mutex.WaitOne(); StreamReader sr = new StreamReader(@"d:\text.txt");
string s = sr.ReadLine();
sr.Close(); // 显示字符串的值
Console.WriteLine("{0}:{1}", Thread.CurrentThread.Name, s);
}
catch (System.Threading.ThreadInterruptedException)
{
Console.WriteLine("{0}:被终止", Thread.CurrentThread.Name);
break;
}
finally
{
// 退出互斥体
mutex.ReleaseMutex();
} // 休眠,将时间片让给消费者
Thread.Sleep(1000);
} // 关闭互斥体
mutex.Close();
Console.WriteLine("{0}:执行完毕", Thread.CurrentThread.Name);
}
}
我们分别编译这两个文件,然后运行Mutex1,他会在另一个窗口中启动Mutex2,可能的结果如下:
6、Semaphore
图书馆都配备有若干台公用计算机供读者查询信息,当某日读者比较多时,必须排队等候。UseLibraryComputer实例用多线程模拟了多人使用多台计算机的过程
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseLibraryComputer
- {
- class Program
- {
- //图书馆拥有的公用计算机
- private const int ComputerNum = 3;
- private static Computer[] LibraryComputers;
- //同步信号量
- public static Semaphore sp = new Semaphore( ComputerNum, ComputerNum);
- static void Main(string[] args)
- {
- //图书馆拥有ComputerNum台电脑
- LibraryComputers = new Computer[ComputerNum];
- for (int i = 0; i <ComputerNum; i++)
- LibraryComputers[i] = new Computer("Computer"+(i+1).ToString());
- int peopleNum = 0;
- Random ran=new Random();
- Thread user;
- System.Console.WriteLine("敲任意键模拟一批批的人排队使用{0}台计算机,ESC键结束模拟……" ,ComputerNum);
- //每次创建若干个线程,模拟人排队使用计算机
- while (System.Console.ReadKey().Key != ConsoleKey.Escape)
- {
- peopleNum = ran.Next(0, 10);
- System.Console.WriteLine("\n有{0}人在等待使用计算机。",peopleNum );
- for (int i = 1; i <= peopleNum; i++)
- {
- user = new Thread(UseComputer);
- user.Start("User" + i.ToString());
- }
- }
- }
- //线程函数
- static void UseComputer(Object UserName)
- {
- sp.WaitOne();//等待计算机可用
- //查找可用的计算机
- Computer cp=null;
- for (int i = 0; i < ComputerNum; i++)
- if (LibraryComputers[i].IsOccupied == false)
- {
- cp = LibraryComputers[i];
- break;
- }
- //使用计算机工作
- cp.Use(UserName.ToString());
- //不再使用计算机,让出来给其他人使用
- sp.Release();
- }
- }
- class Computer
- {
- public readonly string ComputerName = "";
- public Computer(string Name)
- {
- ComputerName = Name;
- }
- //是否被占用
- public bool IsOccupied = false;
- //人在使用计算机
- public void Use(String userName)
- {
- System.Console.WriteLine("{0}开始使用计算机{1}", userName,ComputerName);
- IsOccupied = true;
- Thread.Sleep(new Random().Next(1, 2000)); //随机休眠,以模拟人使用计算机
- System.Console.WriteLine("{0}结束使用计算机{1}", userName,ComputerName);
- IsOccupied = false;
- }
- }
- }
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Threading;
- namespace UseLibraryComputer
- {
- class Program
- {
- //图书馆拥有的公用计算机
- private const int ComputerNum = 3;
- private static Computer[] LibraryComputers;
- //同步信号量
- public static Semaphore sp = new Semaphore( ComputerNum, ComputerNum);
- static void Main(string[] args)
- {
- //图书馆拥有ComputerNum台电脑
- LibraryComputers = new Computer[ComputerNum];
- for (int i = 0; i <ComputerNum; i++)
- LibraryComputers[i] = new Computer("Computer"+(i+1).ToString());
- int peopleNum = 0;
- Random ran=new Random();
- Thread user;
- System.Console.WriteLine("敲任意键模拟一批批的人排队使用{0}台计算机,ESC键结束模拟……" ,ComputerNum);
- //每次创建若干个线程,模拟人排队使用计算机
- while (System.Console.ReadKey().Key != ConsoleKey.Escape)
- {
- peopleNum = ran.Next(0, 10);
- System.Console.WriteLine("\n有{0}人在等待使用计算机。",peopleNum );
- for (int i = 1; i <= peopleNum; i++)
- {
- user = new Thread(UseComputer);
- user.Start("User" + i.ToString());
- }
- }
- }
- //线程函数
- static void UseComputer(Object UserName)
- {
- sp.WaitOne();//等待计算机可用
- //查找可用的计算机
- Computer cp=null;
- for (int i = 0; i < ComputerNum; i++)
- if (LibraryComputers[i].IsOccupied == false)
- {
- cp = LibraryComputers[i];
- break;
- }
- //使用计算机工作
- cp.Use(UserName.ToString());
- //不再使用计算机,让出来给其他人使用
- sp.Release();
- }
- }
- class Computer
- {
- public readonly string ComputerName = "";
- public Computer(string Name)
- {
- ComputerName = Name;
- }
- //是否被占用
- public bool IsOccupied = false;
- //人在使用计算机
- public void Use(String userName)
- {
- System.Console.WriteLine("{0}开始使用计算机{1}", userName,ComputerName);
- IsOccupied = true;
- Thread.Sleep(new Random().Next(1, 2000)); //随机休眠,以模拟人使用计算机
- System.Console.WriteLine("{0}结束使用计算机{1}", userName,ComputerName);
- IsOccupied = false;
- }
- }
- }
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading; namespace UseLibraryComputer
{
class Program
{
//图书馆拥有的公用计算机
private const int ComputerNum = 3;
private static Computer[] LibraryComputers;
//同步信号量
public static Semaphore sp = new Semaphore( ComputerNum, ComputerNum); static void Main(string[] args)
{
//图书馆拥有ComputerNum台电脑
LibraryComputers = new Computer[ComputerNum];
for (int i = 0; i <ComputerNum; i++)
LibraryComputers[i] = new Computer("Computer"+(i+1).ToString());
int peopleNum = 0;
Random ran=new Random();
Thread user;
System.Console.WriteLine("敲任意键模拟一批批的人排队使用{0}台计算机,ESC键结束模拟……" ,ComputerNum);
//每次创建若干个线程,模拟人排队使用计算机
while (System.Console.ReadKey().Key != ConsoleKey.Escape)
{
peopleNum = ran.Next(0, 10);
System.Console.WriteLine("\n有{0}人在等待使用计算机。",peopleNum ); for (int i = 1; i <= peopleNum; i++)
{
user = new Thread(UseComputer);
user.Start("User" + i.ToString());
}
}
} //线程函数
static void UseComputer(Object UserName)
{
sp.WaitOne();//等待计算机可用 //查找可用的计算机
Computer cp=null;
for (int i = 0; i < ComputerNum; i++)
if (LibraryComputers[i].IsOccupied == false)
{
cp = LibraryComputers[i];
break;
}
//使用计算机工作
cp.Use(UserName.ToString()); //不再使用计算机,让出来给其他人使用
sp.Release();
}
} class Computer
{
public readonly string ComputerName = "";
public Computer(string Name)
{
ComputerName = Name;
}
//是否被占用
public bool IsOccupied = false;
//人在使用计算机
public void Use(String userName)
{
System.Console.WriteLine("{0}开始使用计算机{1}", userName,ComputerName);
IsOccupied = true;
Thread.Sleep(new Random().Next(1, 2000)); //随机休眠,以模拟人使用计算机
System.Console.WriteLine("{0}结束使用计算机{1}", userName,ComputerName);
IsOccupied = false;
}
}
}
可能的运行结果:
多线程同步与并发访问共享资源工具—Lock、Monitor、Mutex、Semaphore的更多相关文章
- C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEvent
看下组织结构: System.Object System.MarshalByRefObject System.Threading.WaitHandle System.Threading.Mutex S ...
- 线程系列08,实现线程锁的各种方式,使用lock,Montor,Mutex,Semaphore以及线程死锁
当涉及到多线程共享数据,需要数据同步的时候,就可以考虑使用线程锁了.本篇体验线程锁的各种用法以及线程死锁.主要包括: ※ 使用lock处理数据同步※ 使用Monitor.Enter和Monitor.E ...
- C# 多线程(lock,Monitor,Mutex,同步事件和等待句柄)
本篇从 Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler 的类关系图开始,希望通过本篇的介绍能对常见的线程同步方法有一个整体的认识,而 ...
- 【转】多线程:C#线程同步lock,Monitor,Mutex,同步事件和等待句柄(上)
本篇从Monitor,Mutex,ManualResetEvent,AutoResetEvent,WaitHandler的类关系图开始,希望通过 本篇的介绍能对常见的线程同步方法有一个整体的认识,而对 ...
- Java多线程同步集合--并发库高级应用
一.阻塞队列1.在多线程领域,所谓阻塞,在某些情况下会挂起线程,一旦条件满足,被挂起的线程又会自动被唤醒2.ArrayBlockingQueue(效率高)和LinkedBlockingQueue是两个 ...
- [Java Concurrent] 并发访问共享资源的简单案例
EvenGenerator 是一个偶数生成器,每调用一个 next() 就会加 2 并返回叠加后结果.在本案例中,充当被共享的资源. EvenChecker 实现了 Runnable 接口,可以启动新 ...
- java 多线程 同步 观察者 并发集合的一个例子
//第一版 package com.hra.riskprice; import com.hra.riskprice.SysEnum.Factor_Type; import org.springfram ...
- C#多线程:深入了解线程同步lock,Monitor,Mutex,同步事件和等待句柄(中)
本篇继续介绍WaitHandler类及其子类 Mutex,ManualResetEvent,AutoResetEvent的用法..NET中线程同步的方式多的让人看了眼花缭乱,究竟该怎么去理解呢?其实, ...
- java多线程同步以及线程间通信详解&消费者生产者模式&死锁&Thread.join()(多线程编程之二)
本篇我们将讨论以下知识点: 1.线程同步问题的产生 什么是线程同步问题,我们先来看一段卖票系统的代码,然后再分析这个问题: package com.zejian.test; /** * @author ...
随机推荐
- 开发中常遇到的linux系统配置操作整理
一直以来,工作中使用xshell连接linux虚拟机.常常需要在虚拟机中搭建一个新的Linux系统,为了满足操作需要,必不可少的是一系列配置.之前对这些指令都是记录在云笔记,但是零零散散,每次用时,都 ...
- linux下查看端口是否被占用以及查看所有端口
1.查看服务器端口是否被占用 >lsof -i:8081 2.查看服务器所有端口 >netstat -ntlp 3.查看服务器是否开放某端口 tcp端口:>netstat -ntp ...
- 【Jmeter测试】接口请求完成后,查询数据库结果,检测数据存储是否正确
Jmeter脚本逻辑 发送POST请求,把数据保存到数据库中 发讯数据库,数据库查询结果保存的变量中 使用BeanShell判断数据库查询结果 Jmeter脚本结构 第一个箭头指的是JDBC Conn ...
- 6.把建模工具导出的dea文件导入到three.js程序中
1.使用Three.js渲染导出的DAE 在Three.js中使用Collada(即.dae)文件的话,首先得要用到 ColladaLoader.js. 但是这个ColladaLoader.js并不包 ...
- Flink 部署文档
Flink 部署文档 1 先决条件 2 下载 Flink 二进制文件 3 配置 Flink 3.1 flink-conf.yaml 3.2 slaves 4 将配置好的 Flink 分发到其他节点 5 ...
- ssm-maven 所需添加的所有映射
<dependencies> <!--Mybatis依赖--> <dependency> <groupId>org.mybatis</groupI ...
- js 的filter()方法
filter()方法使用指定的函数测试所有元素,并创建一个包含所有通过测试的元素的新数组. filter()基本语法: arr.filter(callback[, thisArg]) filter() ...
- date命令详解
基础命令学习目录首页 原文链接:https://www.cnblogs.com/qmfsun/p/4598650.html date "+今天是%Y-%d-%m,现在是%H:%M:%S&qu ...
- Linux 学习记录 20170218
一.Linux 硬件查看命令 ----/proc 文件系统是一种内核和内核模块用来向进程(process) 发送信息的机制.我们可以从这个文件里获取到系统的相关信息. 1.显卡信息dmesg ...
- AloneQIan---第一次作业
小学生的噩梦 一.估计与实际 PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 600 720 • Estim ...