多线程基础02
对锁而言,尽可能得使用父对象(级别更大得对象内容)。
通知
通知
是指一个线程告诉另一个线程等待另一个线程回馈结果的操作。
如果没有得到反馈该线程会一直等待,直到另一个线程反馈为止。
通知一般使用Join方法,也可以使用同步类对象
同 步 基 元 | 说 明 |
---|---|
Monitor | 监视器,支持锁定操作,防止一个或多个线程同时访问资源 |
Mutex | 互斥器,支持锁定操作,防止一个或多个线程同时访问资源 |
ReaderWriterLock | 读写锁,支持锁定操作,定义支持单个写线程和多个读线程的锁 |
Semaphore | 信号量,也叫信号灯,阻塞线程直到另一个线程信号通知 |
AutoResetEvent | 事件类,支持通知同步,阻塞线程直到另一个线程设置事件 |
ManualResetEvent | 事件类,支持通知同步,阻塞线程直到另一个线程设置事件 |
同步类对象
AutoResetEvent 类
通知正在等待的线程已发生事件
提供一种通知机制,可以控制线程执行的先后顺序
AutoResetEvent 类/ManualResetEvent类的重要方法
方 法 | 说 明 |
---|---|
Set | 设置并发送信号 |
Reset | 重置信号,也就是使信号无效 |
WaitOne | 等待一个信号,如果没有信号到来则等待 |
ManualResetEvent.WaitAny | 静态方法,等待一个信号数组,信号数组里面有任何信号到都可以,否则等待 |
ManualResetEvent.WaitAll | 静态方法,等待一个信号数组,信号数组里面的信号全部到齐才可以,否则等待 |
创建AutoResetEvent对象
AutoResetEvent myResetEvent = new AutoResetEvent(false);
参数说明:
false表示事件开始是无信号状态,
当参数为true表示创建的事件开始是有信号的,就相当于使用false参数创建事件后立即调用了Set方法。
俗称信号灯
orderEvent.WaitOne() //等待信号,一直等
orderEvent.Set() //发出信号,等待的子线程执行
线程池
现状
创建和销毁线程代价高
线程池
线程池是系统自己维护的线程的集合。
线程池技术减少频繁的线程创建与销毁对系统性能的影响
对于每一个进程系统都会给其创建一个线程池
如果想要执行线程操作,只需要向线程池发出一个执行某个操作的请求即可。
CLR线程池
•1) 最小线程数,线程池的线程总大于等于这个值,一般这个值设置为逻辑CPU数,也就是能充分利用CPU同时执行这些线程。
•2) 最大线程数,默认1000,不建议修改这个值,如果这个值过小,很可能运行的线程的都被阻塞,而排队的线程永远得不到执行。
•3) 线程池是非常智能的,并不会发现可用线程不够马上创建新的线程,而是会有一个延迟以确保真的需要新的线程来补充(因为也不建议线程池中的方法执行时间太长比如超过500毫秒,影响线程池的判断)。线程池的目的就是减少实际线程的创建和回收,重复利用线程来做不同的工作。
ThreadPool
线程池静态类
托管线程池中的线程为后台线程,即它们的 IsBackground 属性为 true。这意味着在所有的前台线程都已退出后,ThreadPool 线程不会让应用程序保持运行。
向线程池提交任务:
原型:
static bool QueueUserWorkItem( WaitCallback callBack, Object state )
举例:
WaitCallback callBackCheck=new WaitCallback(this.Check); ThreadPool.QueueUserWorkItem(callBackCheck,info);
参数WaitCallback原型
委托
public delegate void WaitCallback (Object state);
线程池的一些重要知识
ThreadPool中的Thread不能手动取消,也不用手动开始。所以ThreadPool并不适用比较长的线程。只需要把一个 WaitCallback委托塞给ThreadPool,然后剩下的工作将由系统自动完成。系统会在ThreadPool的线程队列中一一启动线程。
当线程池满时,多余的线程会在队列里排队,当线程池空闲时,系统自动调入排队的线程,以保持系统利用率。
当需要复杂的同步技术,例如事件,或需要对一个线程调用Join方法时线程池就不能满足需求了.
以下情况中不宜使用ThreadPool而应该使用单独的Thread:
1.需要为线程指定详细的优先级
2.线程执行需要很长时间
3.需要前台线程。
4.在线程执行中需要对线程操作,如打断,挂起等
总结
进程和线程相关概述
进程就是一个正在执行的应用程序。是系统进行资源分配的基本单位。
线程是在进程的内部执行的指令序列,共享进程的内存和系统资源。
多线程编程概述
v.Net**下如何创建线程**
Thread
线程的不同状态
ThreadState
线程同步技术
加锁:lock,monitor
通知:AutoResetEvent
线程池
类的扩展方法的简单使用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO.Ports;
using System.Runtime.CompilerServices;
namespace day31test03
{
class Program
{
/// <summary>
/// 扩展方法
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
//SerialPort port = new SerialPort();
Test test = new Test();
test.ddd(4, 5);
test.add(4, 5);
}
}
class Test
{
public void add(int a, int b)
{
Console.WriteLine(a+b);
}
}
static class T
{
public static int ddd(this Test t, int x, int y)
{
return 2*(x - y);
}
}
}
并行的多线程,让CPU多个核都能跑起来。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace day31test05
{
class Program
{
/// <summary>
/// 并行的多线程
/// 多任务
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
Action action = new Action(Dowork);
System.Threading.Tasks.Task task = new Task(action);
task.Start();
Action action1 = new Action(Dowork);
System.Threading.Tasks.Task task1 = new Task(action1);
task1.Start();
Console.Read();
}
public static void Dowork()
{
do
{
} while (true);
}
}
}
匿名方法委托,并行for和foreach
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace day31test06
{
class Program
{
/// <summary>
/// 基于匿名方法的多线程
/// 避免了委托
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
/*System.Threading.Thread t3 = new System.Threading.Thread(a =>
{
Console.WriteLine("基于匿名方法的多线程");
});
t3.Start();*/
//并行for,特点:快
//System.Threading.Tasks.Parallel.For(0, 100, a => { System.Threading.Thread.Sleep(100); Console.WriteLine(System.DateTime.Now); });
//并行foreach,特点:
String[] str = {
"1" , "s", "w"};
System.Threading.Tasks.Parallel.ForEach(str, (item, kk) => {
Console.WriteLine(item); });
Console.Read();
}
}
}