2019年02月27日 14:41
原创作品,转载时请务必以超链接形式标明文章原始出处,否则将追究法律责任。
本片文章主要介绍如何停止多个有关联的线程,举个例子,抗日战争中,我们要消灭一小队鬼子。但是鬼子装备精良,又有迫击炮,又有机枪。因此要求我们每个小分队必须
责任明确,第一分队负责诱敌深入,第二分队负责第一波阻击,第三分队负责埋雷,第四分队负责冲锋。这其中一环没有做好,都会导致大面积伤亡。比如埋雷的雷没弄好,导致第四队下去冲锋送死。或者第一队没有诱敌深入,那第二队也没法完成阻击。所以要求开始前各分队要有个司令员,如果发现其中一个没有准备好,任务取消。
接下来我们就模拟一下这个例子。
CancellationTokenSource tokenSource; CancellationToken cancelToken; List<FightTask> fightTaskList; int THREAD_COUNT = 10; const int CHECK_COUNT_PER_THREAD = 50; private PrecheckResult FightPrepareCheck(PrecheckRequest request) { var result = new PrecheckResult(); tokenSource = new CancellationTokenSource(); cancelToken = tokenSource.Token; var taskList = new List<Task>(); fightTaskList = request.FightTaskList; if (request.FightTaskList.Count / CHECK_COUNT_PER_THREAD < threadCount) { if (request.FightTaskList.Count % CHECK_COUNT_PER_THREAD == 0) { threadCount = request.FightTaskList.Count / CHECK_COUNT_PER_THREAD; } else { threadCount = request.FightTaskList.Count / 50 + 1; } } this.position = 0; PrecheckResult checkFailedResult = null; for (int i = 0; i < threadCount; i++) { Task task = Task.Factory.StartNew(() => { result = this.ProcessTaskCheck(); if (result != null && result.FightTaskCheckResultList != null && result.FightTaskCheckResultList.Any(b => !b.IsSuccess)) { if (checkFailedResult == null) { checkFailedResult = result; } if (!cancelToken.IsCancellationRequested) { tokenSource.Cancel(true); } } }, cancelToken); taskList.Add(task); } try { Task.WaitAll(taskList.ToArray(), 300000); } catch (AggregateException exception) { exception.Handle(ex => { TaskCanceledException tcex = ex as TaskCanceledException; if (tcex != null) { return true; } else { result.IsSuccess = false; result.ErrorMessage = exception.Message; return true; } }); } if (checkFailedResult != null) { return checkFailedResult; } return result; }
在这里开启线程,每个task都会给他一个取消令牌。然后呢我们去执行ProcessTaskCheck方法,当发现任何一个线程的检查结果中有失败的记录,就将这个结果记录下来,并终止所有还未结束的线程。在这里结束线程前最好判断一下当前线程是否已经请求结束了,比如有两个线程同时到达tokenSource.Cancel(true),就会抛出异常。那么即使抛出异常,我们下边会处理这个异常。判断如果是TaskCancelledException,就默认处理。否则将异常返回给result对象,因为TaskCancelledException不是业务异常。
OK,接下来再看一下ProcessTaskCheck方法
private PrecheckResult ProcessTaskCheck() { var checkResult = new PrecheckResult(); var fightTasks = new FightTask[] { }; while (this.position < this.fightTaskList.Count) { lock (objLock) { if (position >= fightTaskList.Count) { break; } if (position <= fightTaskList.Count - CHECK_COUNT_PER_THREAD) { fightTasks = new FightTask[CHECK_COUNT_PER_THREAD]; fightTaskList.CopyTo(position, fightTasks, 0, CHECK_COUNT_PER_THREAD); } else { fightTasks = new FightTask[fightTaskList.Count - position]; fightTaskList.CopyTo(position, fightTasks, 0, fightTasks.Length); } this.position += this.CHECK_COUNT_PER_THREAD; } return this.DoTaskCheck(fightTasks); } }
很简单,每次拿到一批数据,去check,好的,就到这里。
发表评论
匿名
用户评论
暂无评论