一:线程的基本知识
1.Suspend:用于挂起线程
Resume:用于唤醒线程,由于线程的执行情况不可预知,所以使用挂起和唤醒容易发生死锁的情况
2.join():阻塞调用线程,直到该线程终止
3.Abort:抛出ThreadAbortException异常让线程终止,终止后线程不可唤醒
Interrupt:抛出ThreadInterriptException:异常线程终止,通过捕获异常可以继续执行
二 线程的使用
class Program
{
static void Main(string[] args)
{
Thread t1 = new Thread(new ThreadStart(TestMethod));//无参的多线程初始化
Thread t2 = new Thread(new ParameterizedThreadStart(TestMethod));//带参的多线程初始化
t1.IsBackground = true;
t2.IsBackground = true;
t1.Start();
t2.Start("hello");
Console.ReadKey();
}
private static void TestMethod()
{
Thread.Sleep(10000);
Console.WriteLine("不带参数的线程函数");
}
private static void TestMethod(object obj)
{
string datastr = obj as string;
Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
}
}
三 线程池
线程池维护一个请求队列,线程池的代码从队列提取任务,然后委派给线程池的一个线程执行,线程执行完之后不会被立即销毁,这样既可以在后台执行,又可以减少线程的创建销毁带来的资源开销
class Program
{
static void Main(string[] args)
{
ThreadPool.QueueUserWorkItem(TestMethod, "Hello");
Console.ReadKey();
}
private static void TestMethod(object obj)
{
string datastr = obj as string;
Console.WriteLine("带参数的线程函数,参数为:{0}", datastr);
}
}
四 Task 类
使用ThreadPool的QueueUserItem()方法发起一次异步线程执行,但是该方法的最大的问题
是没有一个內建的机制让你知道操作什么时候完成,有没有內建机制在操作完成后获得一个返回值;
为此可以使用System.Threading.Tasks中的Task类
class Program
{
static void Main(string[] args)
{
Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 1000);
t.Start();
t.Wait();//等待task完成执行过程
Console.WriteLine(t.Result);
Console.ReadKey();
}
private static int Sum(int n)
{
Int32 sum = 0;
for (; n > 0; --n)
{
checked { sum += n; }
}
return sum;
}
}
该方法的输出值为从1到1000的加总:500500
一个任务完成之后,它可以启动另一个任务
class Program
{
static void Main(string[] args)
{
Task<Int32> t = new Task<Int32>(n => Sum((Int32)n), 10000);
t.Start();
// t.Wait();//等待task完成执行过程
//Console.WriteLine(t.Result);
Task cwt = t.ContinueWith(task => Console.WriteLine("The result is {0}", t.Result));
Console.ReadKey();
}
private static int Sum(int n)
{
Int32 sum = 0;
for (; n > 0; --n)
{
Thread.Sleep(1);
checked { sum += n; }
}
return sum;
}
}
重写后的方法会输出The result is:500500
五 委托异步执行
委托的异步调用:BeginInvoke()和EndInvoke()
public delegate string MyDelegate(object data);
class Program
{
static void Main(string[] args)
{
MyDelegate myDelegate = new MyDelegate(TestMethod);
IAsyncResult result = myDelegate.BeginInvoke("Thread Param", TestCallBack, "Callback Param");
//异步完成
string resultstr = myDelegate.EndInvoke(result);
Console.ReadLine();
}
//异步回调函数
private static void TestCallBack(IAsyncResult data)
{
Console.WriteLine(data.AsyncState);
}
//线程函数
private static string TestMethod(object data)
{
string datastr = data as string;
return datastr;
}
}
六:
1.Interlocked(原子操作):所有方法都是执行一次原子读或一次写入操作
2.lock()语句避免锁定public类型,否则实例将超出代码的控制范围,定义private对象来锁定
3.Monitor实现线程同步
通过Monitor.Enter()和Monitor.Exit()实现排他锁的获取和释放,获取之后独占资源,不允许其他线程访问
TryEnter方法也可以实现,请求不到资源时不会阻塞等待,可以设置超时时间,获取不到直接返回false
4.ReadWriterLock
当对操作读多写少的时候,为了提高资源利用率,让读操作锁为共享锁,多个线程可以共享读操作,而
写操作独占锁,只允许一个线程操作
5.事件(Event)类实现同步
事件类有两种状态,终止状态和非终止状态终止状态时调用WaitOne,可以请求成功,
通过Set将时间状态设置为终止状态
(1)AutoResetEvent(自动重置事件)
(2)ManualResetEvent(手动重置事件)
6.信号量(Semaphore)
信号量是由内核对象维护的int变量,为0时阻塞线程,大于0时解除阻塞,当一个信号量上的
等待线程解除阻塞后,信号量计数+1.
线程通过WaitOne将信号量减1,通过Release将信号量加1,使用很简单
7.互斥体(Mutex)
独占资源,用法与Semaphore相似
8.跨线程间的同步
通过设置同步对象的名称就可以实现系统级的同步,不同应用程序通过同步对象的名称识别
不同的同步对象
: