您的位置:首页 > 编程语言 > C#

C#多线程

2016-01-06 10:23 531 查看
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();//释放信号量
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: