C#高级编程笔记(17至21章节)线程/任务
17 Visual Studio 2013
控制台用Ctrl+F5可以显示窗口,不用加Console.ReadLine(); F5用于断点调式
程式应该使用发布,因为发布的程序在发布时会进行优化,
21 任务线程和同步
21.2 Parallel类 System.Threading.Tasks
21.2.1 Parallel.For()方法循环 返回ParallelLoopResult类型
多次执行一个任务
执行for循环,其中可能会并行运行迭代。(参数1,始索引(包含),参数2,结束索引(不包含),参数3)
1、Thread.Sleep 是同步延迟,Task.Delay异步延迟。
2、Thread.Sleep 会阻塞线程,Task.Delay不会。
3、Thread.Sleep不能取消,Task.Delay可以。
parallel.For()重载方法For(Int32, Int32, Action( Int32, ParallelLoopState) )
ParallelLoopState.Break() ParallelLoopState.stop()这二个方法后面都要加return;不然后面的语句还是会执行
ParallelLoopState 实例方法 | 作用 | 相当于普通循环的语句 |
stop() | 退出循环,后面的循环体均不执行 | break; |
Break() | 满足相应条件的循环体不执行 | continue; |
ParallelLoopResult.LowestBreakIteration属性取得最后迭代的数值
ParallelLoopResult result =
Parallel.For(, , (int i, ParallelLoopState pls) =>
{
Console.WriteLine("i: {0} task {1}", i, Task.CurrentId);
Thread.Sleep();
if (i > )
pls.Break();
});
Console.WriteLine("Is completed: {0}", result.IsCompleted);
if (!result.IsCompleted) \\ 获取指示循环已完成运行,以便所有的循环迭代期间执行,并且该循环没有收到提前结束的请求。
Console.WriteLine("lowest break iteration: {0}", result.LowestBreakIteration); //从中获取的最低迭代索引 Break 调用。
21.2.2使用Parallel.ForEach()方法
方法使用类似for(),主要用于迭化集合,用于迭化不确定的
string[] data = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve" };
ParallelLoopResult result = Parallel.ForEach<string>(data, s =>
{
Console.WriteLine(s);
});
21.2.3Parallel.Invoke()方法调用多个方法(并行运行)
Parallel.Invoke(方法名1,方法名2);
21.3 任务
StartNew(Action< Object> , Object) 参数1为任务,参数2为object, 在参数1的任务中可以调用object类型,即参数2
var tf = new TaskFactory(); //实例化TaskFactory,然后把任务模式转入其StartNew的方法启动任务
Task t1 = tf.StartNew(TaskMethod, "using a task factory"); Task t2 = Task.Factory.StartNew(TaskMethod, "factory via a task");//使用任务的Factory静态属性来访问TaskFactory调用StartNew var t3 = new Task(TaskMethod, "using a task constructor and Start");//实例化Task,使用t3.Start()来启动
t3.Start(); Task t4 = Task.Run(() => TaskMethod("using the Run method"));//net4.5使用lambda表达式
同步任务
var t1 = new Task(TaskMethod, "run sync"); //如果直接运行,就没有任务,也不是线程池的线程
t1.RunSynchronously();//英语单词运行同步的意思- -
使用单线程任务
var t1 = new Task(TaskMethod, "long running", TaskCreationOptions.LongRunning);//指定任务是长时间运行的不会使用线程池的线程
t1.Start();
任务结果
var t1 = new Task<Tuple<int, int>>(TaskWithResult, Tuple.Create<int, int>(, ));
t1.Start();
Console.WriteLine(t1.Result); //输出 Task<TResult> 的结果值。
t1.Wait(); //等待 Task 完成执行过程
Console.WriteLine("result from task: {0} {1}", t1.Result.Item1, t1.Result.Item2);
21.3.3连续的任务
Task t1 = new Task(DoOnFirst);
Task t2 = t1.ContinueWith(DoOnSecond);//CoutinueWith(方法,TaskContinuationOptions.*****)重载可以在上一个任务成功或失败时执行
t1.Start();//t1执行后运行DoOnSecond任务!后面t2可以继续添加!也可以 t1.ContinueWith(DoOnSecond);
21.3.4 任务层次结构
在父任务创建子任务
Task.Status() 获取此任务的当前状态
21.4.1Paraller.for()方法的取消
var cts = new CancellationTokenSource(); //一个取消标记
cts.Token.ThrowIfCancellationRequested();//如果已有一个取消标记,发送一个异常
cts.Token.Register(() => Console.WriteLine("** token cancelled"));//取消时调用的委托
cts.CancelAfter(); //启动一个任务,在500毫秒后发送一个取消。
try
{
ParallelLoopResult result =
Parallel.For(, ,new ParallelOptions(){CancellationToken = cts.Token},x =>
{
Console.WriteLine("loop {0} started", x);
int sum = ;
for (int i = ; i < ; i++)
{
Thread.Sleep();
sum += i;
}
Console.WriteLine("loop {0} finished", x);
});
}
catch (OperationCanceledException ex)
{
Console.WriteLine(ex.Message);
}
21.4.2 任务的取消
在这里可以理解CancellationTokenSource是一个别一个方法,一个取消事件,在执行CancellationTokenSource.Cancel()方法触发取消
var cts = new CancellationTokenSource();
cts.Token.Register(() => Console.WriteLine("*** task cancelled"));
// send a cancel after 500 ms
cts.CancelAfter();
Task t1 = Task.Run(() =>
{
Console.WriteLine("in task");
for (int i = ; i < ; i++)
{
Thread.Sleep();
CancellationToken token = cts.Token;
if (token.IsCancellationRequested)//这里去检测是否已触发取消
{
Console.WriteLine("取消请求,取消任务范围内的任务。");
token.ThrowIfCancellationRequested();//如果取消请求抛出,如果这一句注释掉会输出"完成任务而不取消"
break;
}
Console.WriteLine("in loop");
}
Console.WriteLine("完成任务而不取消");
}, cts.Token);
try
{
t1.Wait();
}
catch (AggregateException ex)
{
Console.WriteLine("异常: {0}, {1}", ex.GetType().Name, ex.Message);
foreach (var innerException in ex.InnerExceptions)
{
Console.WriteLine("内部异常: {0}, {1}", ex.InnerException.GetType().Name, ex.InnerException.Message);
}
}
21.5 线程池
ThreadPool.GetMaxThreads(out 线程池中辅助线程的最大数目,out 线程池中异步I/O线程的最大数目)
ThreadPool.QueueUserWorkItem(JobForAThread);//将方法排入队列以便执行。 此方法在有线程池线程变得可用时执行。
Thread.CurrentThread.ManagedThreadId //线程的ID
var t1=new Thread(方法);//方法可使用lambda表达式
21.6.1 给线程传递数据
var d = new Data{message ="info"};//给结构体Data值
var t2 = new Thread(方法名);//这里线程启用方法,调用方法(objcet)
t2.Start(d);//这里启用线程,并把结构体传至方法里的objcet类启用
var obj = new 类名();//实例化结构体
var t1 = new Thread(类名.方法名);//类的方法内包含结构体
t1.Start();//启动线程
21.6.2 后台线程
1、当在主线程中创建了一个线程,那么该线程的IsBackground默认是设置为FALSE的。
2、当主线程退出的时候,IsBackground=FALSE的线程还会继续执行下去,直到线程执行结束。
3、只有IsBackground=TRUE的线程才会随着主线程的退出而退出。
4、当初始化一个线程,把Thread.IsBackground=true的时候,指示该线程为后台线程。后台线程将会随着主线程的退出而退出。
5、原理:只要所有前台线程都终止后,CLR就会对每一个活在的后台线程调用Abort()来彻底终止应用程序。
var t1 =new Thread(ThreadMain){Name="test1",IsBackground=false}; \\false表示是前台线程
static void ThreadMain()
{Console.WriteLine("调进线程的名称为{0}",Thread.CurrentThread.Name) ;}
21.6.3 线程的优先级
ThreadA.Priority = ThreadPriority.AboveNormal;//系统优先执行优先级较高的线程,但这只意味着优先级较高的线程占有更多的CPU时间,并不意味着一定要先执行完优先级较高的线程,才会执行优先级较低的线程。这一点从运行结果中也可以看出,线程B 偶尔会出现在主线程和线程A前面。
21.6.4 控制线程
线程在调用start时线程状态Unstarted,线程调度器运行时Running,而当Sleep时是WaitSleepJoin状态
Thread.ThreadState 当前线程状态 Thread.Abort()抛出异常,Thread.ResetAbort()重置继续运行线程 相关链接
21.7.1争用条件
就是说一个变量,在二个线程中同时判断,线程1判断完未到修改时,线程2也在判断,因还线程1还没有修改,所以判断是通过的!然后二个线程都同时去修改变量,变量之前i++的,现在就是i=i+2了! 所以为了解决这问题
可以锁定共享对象(只有引用类型才能锁定 int strate =5 ;不能锁定strate ) lock(strate){程序},锁定放判断前,因不是引用类型能锁定,可以定义一个object变量(详细查看书本)
21.7.2 死锁
二个线程,线程1和2有二个锁,线程1锁了锁一后想锁二,但是锁二在线程2里锁着时,而线程2又在等待锁一,然后程序就死锁了!
21.8同步
原子操作:就是在执行某一操作时不被打断.相关
互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的。
同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问。在大多数情况下,同步已经实现了互斥,特别是所有写入资源的情况必定是互斥的。少数情况是指可以允许多个访问者同时访问资源。
21.8.1
lock(typof(staticclass))//锁定静态成员
lock(this)设置为线程安全,一次只有一个线程访问相同的实例
本节主要说的是lock使用方法,使用时应该放在正确的位置!不应放在类内!相关内容请查看书本
21.8.2 Interlocked类 System.Threading
return Interlocked.Increment(ref state); //以原子操作的形式递增指定变量的值并存储结果。
21.8.3Monitor类 System.Threading
Monitor. Enter(Object) 方法获取指定对象上的排他锁。 Monitor. Exit(Object) 方法释放指定对象上的排他锁。
21.8.4SpinLock结构 ,因为是结构,把一个变量赋予另一个变量会创建一个副本,所以是通过引用传送SPinLock
与Monitor相似方法一样, 在有大量的锁定,且锁定的时间总是非常短
21.8.5 WaitHandle类 (单词等待句柄的意思)
封装等待对共享资源的独占访问的操作系统特定的对象。 这里略过!下次再看
21.8.6 Mutex类 互斥 派生自基类WaitHandle
if(mutax.WaitOne())//获得互斥锁
{
try{}//同步程序
finally {mutax.ReleaseMutax();}//释放互斥
}
else
{
//等待时发生了一些问题
}
bool createdNew;
var mutex = new Mutex(false, "SingletonWinAppMutex", out createdNew);//使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权的 Boolean 值初始化 Mutex 类的新实例。
if (!createdNew)
{ }
21.8.7Semaphore类 信号量
信号量,如三个物理端口可用,就允许3个线程同时访问I/O端口,但第4个线程需要等待3个线程中的一个释放资源。
可以理解为信号量主要是设置同时能使用多少个线程可以访问资源.
SemapHoreSlim是Semaphore的轻化型版本
using System;
using System.Threading;
using System.Threading.Tasks; namespace Wrox.ProCSharp.Threading
{
class Program
{
static void Main()
{
int taskCount = ; //6个任务数
int semaphoreCount = ;
var semaphore = new SemaphoreSlim(semaphoreCount, semaphoreCount);//同时指定可同时授予的请求的初始数量和最大数量
var tasks = new Task[taskCount]; for (int i = ; i < taskCount; i++)
{
tasks[i] = Task.Run(() => TaskMain(semaphore));
} Task.WaitAll(tasks); Console.WriteLine("所有的任务完成了");
} static void TaskMain(SemaphoreSlim semaphore)
{
bool isCompleted = false;
while (!isCompleted)
{
if (semaphore.Wait())//阻止当前线程,直至它可进入 SemaphoreSlim 为止。,最长等待600毫秒
{
try
{
Console.WriteLine("任务 {0} 锁信号量", Task.CurrentId);
Thread.Sleep();
}
finally
{
Console.WriteLine("任务 {0} 释放信号量", Task.CurrentId);
semaphore.Release();
isCompleted = true;
}
}
else
{
Console.WriteLine("超时任务 {0}; 等待 再一次",
Task.CurrentId);
}
}
}
}
}
21.8.8 Event类
理解就是在类上声明事件,然后再调main最后等待事件触发(看书本)
static void Main()
{
const int taskCount = ;
var mEvents = new ManualResetEventSlim[taskCount];//手动重置事件类数组
var waitHandles = new WaitHandle[taskCount];//资源独占的操作 这里用于外调事件
var calcs = new Calculator[taskCount];
for (int i = ; i < taskCount; i++)
{
int i1 = i;//这个变量用于计算用的测试变量
mEvents[i] = new ManualResetEventSlim(false);//初始状态设置为非终止
waitHandles[i] = mEvents[i].WaitHandle;//获取ManualResetEventSlim 等于接收事件
calcs[i] = new Calculator(mEvents[i]);//设置新的Calculator实例为的手动重置事件为非终止事件
Task.Run(() => calcs[i1].Calculation(i1 + , i1 + ));
}
for (int i = ; i < taskCount; i++)
{
int index = WaitHandle.WaitAny(waitHandles);
if (index == WaitHandle.WaitTimeout)
{
Console.WriteLine("时间结束!!");
}
else
{
mEvents[index].Reset();
Console.WriteLine("完成任务 {0}, 结果: {1}",index, calcs[index].Result);
}
}
}
public class Calculator
{
private ManualResetEventSlim mEvent; //手动重置事件
private CountdownEvent cEvent; //表示在计数变为零时会得到信号通知的同步基元。 public int Result { get; private set; } public Calculator(ManualResetEventSlim ev)
{
this.mEvent = ev;
}
public void Calculation(int x, int y)
{
Console.WriteLine("任务 {0} 开始计算", Task.CurrentId);
Thread.Sleep(new Random().Next());
Result = x + y; // signal the event—completed!
Console.WriteLine("任务 {0} 准备好了", Task.CurrentId);
mEvent.Set();//将事件状态设置为有信号,从而允许一个或多个等待该事件的线程继续
// cEvent.Signal();
}
}
1
21.8.9 Barrier类 相关
因为Main()也是参与者,所以 var barrier = new Barrier(numberTasks +1 ); 数量是3个
barrier.SignalAndWait();//发出参与者已达到屏障并等待所有其他参与者也达到屏障。
barrier.RemoveParticipant();//通知 Barrier,告知其将会减少一个参与者。
21.8.10 RreaderWriterLockSlim类
允许多个读取器,但只能有一个写入器锁定
private static ReaderWriterLockSlim rwl = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
rwl.EnterReadLock; //尝试进入读取模式锁定状态。
rwl.TryEnterWriteLock; //尝试进入写入模式锁定状态,可以选择超时时间。
rwl.ExitReadLock();//减少读取模式的递归计数,并在生成的计数为 0(零)时退出读取模式。
21.9 Timer 类
private static void ThreadingTimer()
{
using (var t1 = new System.Threading.Timer(TimeAction, null, TimeSpan.FromSeconds(),TimeSpan.FromSeconds()))//参数1方法名,参数2回调方法要使用的信息,参数3:启动延时时间(秒),参数4方法之间的间隔时间
{
Thread.Sleep();
}
}
var t1 = new System.Timers.Timer();
t1.AutoReset = true;//触发事件多次
t1.Elapsed += TimeAction; //间隔事件的方法
t1.Start();
Thread.Sleep();
t1.Stop();
t1.Dispose();
21.10 TPL DataFlow数据流 参考
因暂没找到NuGet包无法做测试!!暂时跳过,
22 安全性
0.0学习暂停,考滤学习的重要性,后面转为SQL的学习!等学习完SQL再继续!(未完,待更新......)
C#高级编程笔记(17至21章节)线程/任务的更多相关文章
- C#高级编程笔记 (6至10章节)运算符/委托/字符/正则/集合
数学的复习,4^-2即是1/4/4的意思, 4^2是1*2*2的意思,而10^-2为0.01! 7.2运算符 符号 说明 例 ++ 操作数加1 int i=3; j=i++; 运算后i的值为4,j ...
- C#高级编程笔记(22至25章节)文件\注册表\权限\事务
22安全(using System.Security.Principal;) AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.Wi ...
- C#高级编程笔记 (1至6章节)数组,类/方法/泛型
2.3变量 var 类型推断 type 类的分类 如:type nametype = name.GetType(); //取变量name的类型 const 常量 const int painame ...
- Android高级编程笔记(四)深入探讨Activity(转)
在应用程序中至少包含一个用来处理应用程序的主UI功能的主界面屏幕.这个主界面一般由多个Fragment组成,并由一组次要Activity支持.要在屏幕之间切换,就必须要启动一个新的Activity.一 ...
- UNIX环境高级编程笔记之文件I/O
一.总结 在写之前,先唠几句,<UNIX环境高级编程>,简称APUE,这本书简直是本神书,像我这种小白,基本上每看完一章都是“哇”这种很吃惊的表情.其实大概三年前,那会大三,我就买了这本书 ...
- javascript高级编程笔记01(基本概念)
1.在html中使用JavaScript 1. <script> 元素 <script>定义了下列6个属性: async:可选,异步下载外部脚本文件. charset:可选, ...
- C#高级编程笔记之第三章:对象和类型
类和结构的区别 类成员 匿名类型 结构 弱引用 部分类 Object类,其他类都从该类派生而来 扩展方法 3.2 类和结构 类与结构的区别是它们在内存中的存储方式.访问方式(类似存储在堆上的引用类型, ...
- C#高级编程笔记之第二章:核心C#
变量的初始化和作用域 C#的预定义数据类型 流控制 枚举 名称空间 预处理命令 C#编程的推荐规则和约定 变量的初始化和作用域 初始化 C#有两个方法可以一确保变量在使用前进行了初始化: 变量是字段, ...
- C#高级编程笔记2016年10月12日 运算符重载
1.运算符重载:运算符重重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加.相乘或逻辑操作等.例如,语句if(a==b).对于类,这个语句在默认状态下会比较引 ...
随机推荐
- NOIp 数据结构专题总结 (1):STL、堆、并查集、ST表、Hash表
系列索引: NOIp 数据结构专题总结 (1) NOIp 数据结构专题总结 (2) STL structure STL 在 OI 中的运用:https://oi.men.ci/stl-in-oi/ s ...
- SpringMVC-设计模式
MVC 设计不仅限于 Java Web 应用,还包括许多应用,比如前端.PHP..NET 等语言.之所以那么做的根本原因在于解耦各个模块. MVC 是 Model.View 和 Controller ...
- Js获取屏幕宽度、高度
document.body.clientWidth ==> BODY对象宽度 document.body.clientHeight ==> BODY对象高度 document.docume ...
- linux-批量修改目录下后缀shell
#!/bin/bashcd /optrename .sh .shell *.shecho "后缀修改成功"
- php中的构造函数与析构函数
PHP面向对象——构造函数.析构函数 __construct.__destruct__construct 构造方法,当一个对象创建时调用此方法,使用此方法的好处是:可以使构造方法有一个独一无二的名称, ...
- 《图解设计模式》读书笔记3-1 Singleton模式
目录 单例模式 饿汉式 懒汉式 线程安全的懒汉式 单例模式 确保任何情况下都只有一个实例 饿汉式 public class Singleton { //在类被加载的时候运行一次,这是本类构造函数的唯一 ...
- Learn Python the hard way, ex35 分支和函数
#!/usr/bin/python #coding:utf-8 from sys import exit def gold_room(): print "this room is full ...
- springboot异步任务、定时任务
打开浏览器 http://localhost:8080/hello ,连续刷新可以看到不会 等待 3秒时间了,pom.xml controller service 代码如下. -----------S ...
- html5_websql
var db = openDatabase('mydb', '1.0', 'Test DB', 2 * 1024 * 1024); var msg; db.transaction(function ...
- adb常用命令-android学习第一天
转载出处:http://www.cnblogs.com/xiaoxuetu/ 转载来源:https://www.cnblogs.com/xiaoxuetu/p/3411214.html 平时开发and ...