标签:
1.使用多线程的几种方式
class Program { static void Main(string[] args) { for (int i = 0; i < 30; i++) { //ThreadStart是一个委托,这个委托的定义为void ThreadStart(),没有参数与返回值。 ThreadStart threadStart = new ThreadStart(Calculate); Thread thread = new Thread(threadStart); thread.Start(); } Thread.Sleep(2000); Console.Read(); } public static void Calculate() { DateTime time = DateTime.Now;//得到当前时间 Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间 Console.WriteLine(time.Minute + ":" + time.Millisecond); } }
class Program { static void Main(string[] args) { for (int i = 0; i < 30; i++) { //ParameterThreadStart委托定义为void ParameterizedThreadStart(object state),有一个参数但是没有返回值。 ParameterizedThreadStart tStart = new ParameterizedThreadStart(Calculate); Thread thread = new Thread(tStart); thread.Start(i);//传递参数 } Thread.Sleep(2000); Console.Read(); } public static void Calculate(object arg) { Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间 Console.WriteLine(arg); } }
class Program { static void Main(string[] args) { //使用线程类可以有多个参数与多个返回值,十分灵活! MyThread mt = new MyThread(100); ThreadStart threadStart = new ThreadStart(mt.Calculate); Thread thread = new Thread(threadStart); thread.Start(); //等待线程结束 while (thread.ThreadState != ThreadState.Stopped) { Thread.Sleep(10); } Console.WriteLine(mt.Result);//打印返回值 Console.Read(); } } public class MyThread//线程类 { public int Parame { set; get; }//参数 public int Result { set; get; }//返回值 //构造函数 public MyThread(int parame) { this.Parame = parame; } //线程执行方法 public void Calculate() { Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间 Console.WriteLine(this.Parame); this.Result = this.Parame * ra.Next(10, 100); } }
class Program { static void Main(string[] args) { int Parame = 100;//当做参数 int Result = 0;//当做返回值 //使用匿名方法启动线程可以有多个参数和返回值,而且使用非常方便! ThreadStart threadStart = new ThreadStart(delegate() { Random ra = new Random();//随机数对象 Thread.Sleep(ra.Next(10, 100));//随机休眠一段时间 Console.WriteLine(Parame);//输出参数 Result = Parame * ra.Next(10, 100);//计算返回值 }); Thread thread = new Thread(threadStart); thread.Start();//多线程启动匿名方法 //等待线程结束 while (thread.ThreadState != ThreadState.Stopped) { Thread.Sleep(10); } Console.WriteLine(Result);//打印返回值 Console.Read(); } }
2.使用委托开启多线程(多线程深入)
//1、用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程 //BeginInvoke方法可以使用线程异步地执行委托所指向的方法。 //然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值) //,或是确定方法已经被成功调用。 class Program { private delegate int NewTaskDelegate(int ms); private static int newTask(int ms) { Console.WriteLine("任务开始"); Thread.Sleep(ms); Random random = new Random(); int n = random.Next(10000); Console.WriteLine("任务完成"); return n; } static void Main(string[] args) { NewTaskDelegate task = newTask; IAsyncResult asyncResult = task.BeginInvoke(2000, null, null); //EndInvoke方法将被阻塞2秒 int result = task.EndInvoke(asyncResult); Console.WriteLine(result); Console.Read(); } }
//使用IAsyncResult.IsCompleted属性来判断异步调用是否完成 class Program { private delegate int NewTaskDelegate(int ms); private static int newTask(int ms) { Console.WriteLine("任务开始"); Thread.Sleep(ms); Random random = new Random(); int n = random.Next(10000); Console.WriteLine("任务完成"); return n; } static void Main(string[] args) { NewTaskDelegate task = newTask; IAsyncResult asyncResult = task.BeginInvoke(2000, null, null); //等待异步执行完成 while (!asyncResult.IsCompleted) { Console.Write("*"); Thread.Sleep(100); } // 由于异步调用已经完成,因此, EndInvoke会立刻返回结果 int result = task.EndInvoke(asyncResult); Console.WriteLine(result); Console.Read(); } }
//3、使用WaitOne方法等待异步方法执行完成 //WaitOne的第一个参数表示要等待的毫秒数,在指定时间之内,WaitOne方法将一直等待, //直到异步调用完成,并发出通知,WaitOne方法才返回true。当等待指定时间之后, //异步调用仍未完成,WaitOne方法返回false,如果指定时间为0, //表示不等待,如果为-1,表示永远等待,直到异步调用完成。 class Program { private delegate int NewTaskDelegate(int ms); private static int newTask(int ms) { Console.WriteLine("任务开始"); Thread.Sleep(ms); Random random = new Random(); int n = random.Next(10000); Console.WriteLine("任务完成"); return n; } static void Main(string[] args) { NewTaskDelegate task = newTask; IAsyncResult asyncResult = task.BeginInvoke(2000, null, null); //等待异步执行完成 while (!asyncResult.AsyncWaitHandle.WaitOne(100, false)) { Console.Write("*"); } int result = task.EndInvoke(asyncResult); Console.WriteLine(result); Console.Read(); } }
//4、使用回调方式返回结果 //要注意的是“my.BeginInvoke(3,300, MethodCompleted, my)”,BeginInvoke方法的参数传递方式:前面一部分(3,300)是其委托本身的参数。 //倒数第二个参数(MethodCompleted)是回调方法委托类型,他是回调方法的委托,此委托没有返回值,有一个IAsyncResult类型的参数, //当method方法执行完后,系统会自动调用MethodCompleted方法。 //最后一个参数(my)需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托,这个值可以使用IAsyncResult.AsyncState属性获得。 class Program { private delegate int MyMethod(int second, int millisecond); //线程执行方法 private static int method(int second, int millisecond) { Console.WriteLine("线程休眠" + (second * 1000 + millisecond) + "毫秒"); Thread.Sleep(second * 1000 + millisecond); Random random = new Random(); return random.Next(10000); } //回调方法 private static void MethodCompleted(IAsyncResult asyncResult) { if (asyncResult == null || asyncResult.AsyncState == null) { Console.WriteLine("回调失败!!!"); return; } int result = (asyncResult.AsyncState as MyMethod).EndInvoke(asyncResult); Console.WriteLine("任务完成,结果:" + result); } static void Main(string[] args) { MyMethod my = method; IAsyncResult asyncResult = my.BeginInvoke(3, 300, MethodCompleted, my); Console.WriteLine("任务开始"); Console.Read(); } }
//5、其他组件的BeginXXX和EndXXX方法 //在其他的.net组件中也有类似BeginInvoke和EndInvoke的方法,如System.Net.HttpWebRequest类的BeginGetResponse和EndGetResponse方法。 //其使用方法类似于委托类型的BeginInvoke和EndInvoke方法,例如: class Program { //回调函数 private static void requestCompleted(IAsyncResult asyncResult) { if (asyncResult == null || asyncResult.AsyncState == null) { Console.WriteLine("回调失败"); return; } HttpWebRequest hwr = asyncResult.AsyncState as HttpWebRequest; HttpWebResponse response = (HttpWebResponse)hwr.EndGetResponse(asyncResult); StreamReader sr = new StreamReader(response.GetResponseStream()); string str = sr.ReadToEnd(); Console.WriteLine("返回流长度:" + str.Length); } static void Main(string[] args) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.baidu.com"); //异步请求 IAsyncResult asyncResult = request.BeginGetResponse(requestCompleted, request); Console.WriteLine("任务开始"); Console.Read(); } }
3.多线程访问GUI界面的处理
public partial class Form1 : Form { public Form1() { InitializeComponent(); } //使用该方式不会有无响应的情况发生,强烈建议使用该方式。 //此方式不会发生界面无响应的关键点:调用this.textBox1.Invoke(action) //就是在拥有this.textBox1对象的线程(不一定是当前线程,多数是主线程)上调用action委托, //若action委托指向的方法执行时间过长就会使得界面无响应!而该方式中action委托指向的方法执行时间极为短。 private void button1_Click(object sender, EventArgs e) { Thread thread = new Thread(Flush);
//当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。 thread.IsBackground = true; thread.Start(); } //线程执行的方法 private void Flush() { //定义委托 Action action = delegate() { this.textBox1.AppendText("不在当前" + DateTime.Now.ToString() + "\r\n"); }; while (true) { //判断能否到当前线程操作该组件 if (this.textBox1.InvokeRequired) { //不在当前线程上操作 this.textBox1.Invoke(action);//调用委托 } else { //在当前线程上操作 this.textBox1.AppendText("在当前" + DateTime.Now.ToString() + "\r\n"); } Thread.Sleep(1000); } } private void button2_Click(object sender, EventArgs e) { this.textBox1.AppendText("Btn2点击了" + DateTime.Now.ToString() + "\r\n"); } //使用这种方法时,这个btn会被锁定,其他的btn点击无效 private void button3_Click(object sender, EventArgs e) { while (true) { this.textBox1.AppendText("在当前" + DateTime.Now.ToString() + "\r\n"); Thread.Sleep(1000); } } }
public partial class Form1 : Form { public Form1() { InitializeComponent(); //指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。 backgroundWorker1.WorkerReportsProgress = true; //DoWork—当执行BackgroundWorker.RunWorkerAsync方法时会触发该事件,并且传递DoWorkEventArgs参数 backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork); //操作处理中获得的处理状态变化,通过BackgroundWorker.ReportProgress方法触发该事件 backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged); //异步操作完成或中途终止会触发该事件。如果需要提前终止执行后台操作,可以调用 backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted); } private void button1_Click(object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync();//开始执行后台操作。引发 DoWork 事件 } //处理事务事件 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { //初始化进度条 this.progressBar1.Maximum = 100; this.progressBar1.Minimum = 0; //模拟事物处理 for (int i = 0; i < 100; i++) { Thread.Sleep(10); //局部操作完成事件触发 this.backgroundWorker1.ReportProgress(i, null); } } //局部操作完成时执行的方法 private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { this.progressBar1.Value = e.ProgressPercentage;//设置进度条值 } //事物处理完成时触发 private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { MessageBox.Show(null, "工作线程完成!", "提示"); } }
//许多时候,我们需要用多线程,但是又不希望线程的数量过多,这就是线程池的作用,.Net为我们提供了现成的线程池ThreadPool。 //每一个进程都有一个线程池,线程池的默认大小是25,我们可以通过SetMaxThreads方法来设置其最大值。 //注意:因为WaitCallback委托的原型是void WaitCallback(object state),那没有办法,我们只能将多个参数封装到一个Object中。 class Program { //线程方法 public static void ThreadProc(object i) { Console.WriteLine(i.ToString()); Thread.Sleep(1000); } public static void Main() { ThreadPool.SetMaxThreads(3, 3);//设置线程池 for (int i = 0; i < 20; i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc), "线程" + i); } //Console.WriteLine("运行结束"); Console.Read(); } }
5.线程同步
//(1)代码块同步(Monitor与lock) //使用Monitor类的使用与lock关键字的使用在实现原理上相同。 //Monitor.Enter 方法: 在指定对象上获取排他锁。 //Monitor.TryEnter 方法:试图获取指定对象的排他锁。 //Monitor.Exit 方法: 释放指定对象上的排他锁。 //Monitor.Wait 方法: 释放对象上的锁并阻塞当前线程,直到它重新获取该锁。 //Monitor.Pulse 方法: 通知等待队列中的线程锁定对象状态的更改。 //Monitor.PulseAll 方法:通知所有的等待线程对象状态的更改。 class Program { private int Count = 0; //线程执行方法 public void ThreadProc() { //Monitor.Enter(this); //Thread.Sleep(200); //Count++; //Console.WriteLine(Count); //Monitor.Exit(this); //等同于 lock (this) { Thread.Sleep(200); Count++; Console.WriteLine(Count); } } public static void Main() { Program p = new Program(); for (int i = 0; i < 100; i++) { Thread t = new Thread(p.ThreadProc); t.Start(); } Console.Read(); } }
//使用WaitAll静态方法 //理解AutoResetEvent.WaitAll(Waits)静态方法:WaitAll静态方法就是阻塞当前线程,直到Waits数组里的所有元素都调用Set()方法发送信号,再继续执行当前线程。 class Program { public static void Main() { AutoResetEvent[] Waits = new AutoResetEvent[10]; for (int i = 0; i < 10; i++) { int temp = i; Waits[temp] = new AutoResetEvent(false); Action thread = delegate() { //线程执行方法 Console.WriteLine("线程:" + temp); Thread.Sleep(1000); Waits[temp].Set();//发送线程执行完毕信号 }; ThreadStart ts = new ThreadStart(thread); Thread t = new Thread(ts); t.Start(); } AutoResetEvent.WaitAll(Waits);//等待Waits中的所有对象发出信号 Console.WriteLine("线程全部执行完毕!"); Console.Read(); } }
//使用WaitAny静态方法 //理解AutoResetEvent.WaitAny(Waits)静态方法:WaitAny静态方法就是阻塞当前线程,只要Waits数组有一个元素调用Set()方法发送信号,就继续执行当前线程。 class Program { public static void Main() { AutoResetEvent[] Waits = new AutoResetEvent[10]; for (int i = 0; i < 10; i++) { Waits[i] = new AutoResetEvent(false);//初始化Waits } for (int i = 0; i < 10; i++) { int temp = i; Action thread = delegate() { if (temp > 0) { AutoResetEvent.WaitAny(Waits);//等待上一个线程执行完毕 } //线程执行方法 Thread.Sleep(1000); Waits[temp].Set();//发送线程执行完毕信号 Console.WriteLine("线程:" + temp + "执行完毕"); }; ThreadStart ts = new ThreadStart(thread); Thread t = new Thread(ts); t.Start(); } Console.Read(); }
//使用WaitOne成员方法 //理解Wait.WaitOne()成员方法:WaitOne方法就是阻塞当前线程,只要Wait对象调用了Set()方法发送信号,就继续执行当前线程。 class Program { public static void Main() { AutoResetEvent Wait = new AutoResetEvent(false); for (int i = 0; i < 10; i++) { Action thread = delegate() { //线程执行方法 Thread.Sleep(1000); Wait.Set();//发送线程执行完毕信号 Console.WriteLine("线程:" + i + "执行完毕"); }; ThreadStart ts = new ThreadStart(thread); Thread t = new Thread(ts); t.Start(); Wait.WaitOne();//等待调用 Waits.Set() } Console.Read(); } }
class Program { private static ManualResetEvent Wait = new ManualResetEvent(false); public static void Main() { Wait.Set();//设置线程状态为允许执行 Thread thread1 = new Thread(Method); thread1.Start("线程1"); Thread.Sleep(1000);//等待线程1执行 Wait.Reset();//必须手动复位线程状态,使状态为不允许执行 Thread thread2 = new Thread(Method); thread2.Start("线程2");//线程2将会一直等待信号 Console.WriteLine("主线程结束"); Console.Read(); } //线程执行方法 private static void Method(Object o) { Wait.WaitOne();//等待信号 Console.WriteLine(o.ToString()); } }
//Interlocked类为多个线程共享的变量提供原子操作。 //原子操作:Interlocked.Increment()操作是一个原子操作,作用是:Count++ 。 //原子操作,就是不能被更高等级中断抢夺优先的操作。由于操作系统大部分时间处于开中断状态, //所以,一个程序在执行的时候可能被优先级更高的线程中断。而有些操作是不能被中断的, //不然会出现无法还原的后果,这时候,这些操作就需要原子操作。就是不能被中断的操作。 class Program { private static int Count = 0; static void Main(string[] args) { for (int i = 0; i < 100; i++) { Thread thread = new Thread(Method); thread.Start("线程" + i); } Thread.Sleep(1000 * 3);//休眠足够的时间等待所有线程执行完毕 Console.WriteLine("操作后的结果:" + Program.Count); Console.ReadLine(); } //线程执行方法 private static void Method(Object o) { Thread.Sleep(500); //原子操作,类似:Program.Count++ Interlocked.Increment(ref Program.Count); //Program.Count++;//非原子操作 Console.WriteLine(o.ToString()); } }
//使用Monitor或Mutex进行同步控制的问题:由于独占访问模型不允许任何形式的并发访问,这样的效率总是不太高。 //许多时候,应用程序在访问资源时是进行读操作,写操作相对较少。为解决这一问题,C#提供了System.Threading.ReaderWriterLock类以适应多用户读/单用户写的场景。 //该类可实现以下功能:如果资源未被写操作锁定,那么任何线程都可对该资源进行读操作锁定,并且对读操作锁数量没有限制,即多个线程可同时对该资源进行读操作锁定, //以读取数据。如果资源未被添加任何读或写操作锁,那么一个且仅有一个线程可对该资源添加写操作锁定,以写入数据。简单的讲就是:读操作锁是共享锁, //允许多个线程同时读取数据;写操作锁是独占锁,同一时刻,仅允许一个线程进行写操作。 //ReaderWriterLock类:定义支持单个写线程和多个读线程的锁。 //ReaderWriterLockSlim类:表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问。 class Program { private static int Count = 0;//资源 static ReaderWriterLock rwl = new ReaderWriterLock();//读、写操作锁 static void Main(string[] args) { for (int i = 0; i < 10; i++) { Thread thread = new Thread(Read);//读线程 thread.Start("线程" + i); } for (int i = 0; i < 10; i++) { Thread thread = new Thread(Write);//写线程 thread.Start("--线程" + i); } Console.ReadKey(); } private static void Read(Object o)//读数据 { rwl.AcquireReaderLock(1000 * 20); //申请读操作锁,在20s内未获取读操作锁,则放弃 Console.WriteLine(o.ToString() + "读取数据:" + Program.Count); Thread.Sleep(500); rwl.ReleaseReaderLock();//释放读操作锁 } private static void Write(Object o)//写数据 { rwl.AcquireWriterLock(1000 * 20);//申请写操作锁,在20s内未获取写操作锁,则放弃 Thread.Sleep(500); Console.WriteLine(o.ToString() + "写数据:" + (++Program.Count)); rwl.ReleaseWriterLock();//释放写操作锁 } }
private static Semaphore semaphore = new Semaphore(0, 5);//初始化信号量 static void Main(string[] args) { for (int i = 0; i < 10; i++) { Thread thread = new Thread(Method); thread.Start("线程" + i); } semaphore.Release(2);//释放信号量2个 Console.WriteLine("主线程运行完毕!"); Console.Read(); } //线程执行方法 private static void Method(object o) { semaphore.WaitOne();//等待信号量 Thread.Sleep(1000); Console.WriteLine(o.ToString()); semaphore.Release();//释放信号量 }
标签:
原文地址:http://www.cnblogs.com/lgxlsm/p/5092418.html