程序框架
主界面:
主窗体xaml:
<Grid Background="#FFDEDED4">
<TextBox x:Name="txtCountThreads" HorizontalAlignment="Left" Height="45" Margin="31,23,0,0" Text="7" TextWrapping="Wrap" VerticalAlignment="Top" Width="112" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontSize="16" FontWeight="Bold"/>
<Button x:Name="btnStart" Content="Start" Click="btnStart_Click" HorizontalAlignment="Left" Height="45" Margin="531,23,0,0" VerticalAlignment="Top" Width="112" FontSize="16" FontWeight="Bold"/>
<Button x:Name="btnStop" Content="Stop" Click="btnStop_Click" HorizontalAlignment="Left" Height="45" Margin="656,23,0,0" VerticalAlignment="Top" Width="112" FontSize="16" FontWeight="Bold" Foreground="#FFE65429"/>
<ScrollViewer x:Name="scrollView" VerticalScrollBarVisibility="Auto"
Height="459"
Width="736"
Margin="0,93,0,0"
HorizontalScrollBarVisibility="Disabled">
<TextBlock x:Name="txtPayload" Text="" Background="White"/>
</ScrollViewer>
</Grid>
主窗体交互逻辑:
public partial class MainWindow : Window
{
ManagerJob managerJob;
public MainWindow()
{
InitializeComponent();
}
//更新数据显示
public void AddMessageToPayload()
{
this.Dispatcher.Invoke(() =>
{
/// using '=' Instead of '+=' to save memory
this.txtPayload.Text += ManagerJob.payloadString.ToString();//显示有效负载信息
this.scrollView.ScrollToEnd();
if (ManagerJob.payloadString.ToString().Contains("Manager task finished work"))
{
btnStart.IsEnabled = true;
}
});
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
string countStr = txtCountThreads.Text;
try
{
int count = Int32.Parse(countStr);//任务数
if(count <= 0 )
{
MessageBox.Show("Enter number > 0");
}
else
{
managerJob = new ManagerJob(count);//
// Add reference to external method to update data
ManagerJob.addMessage += AddMessageToPayload; //添加对外部方法的引用以更新数据
managerJob.Start();
btnStart.IsEnabled = false;
}
}
catch (FormatException)
{
MessageBox.Show("Can't Parsed '{0}'", countStr);
}
}
private void btnStop_Click(object sender, RoutedEventArgs e)
{
this.managerJob.Stop();
}
}
任务类 TaskJob.cs:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1.app.classes
{
class TaskJob
{
private int timeSpan;//时间 毫秒
private Task task;//任务
//任务构造函数:动作,时间
public TaskJob(Action action, int timeSpan)
{
this.task = new Task(action);
this.TimeSpan = timeSpan;
}
//任务成功完成信息
public string IsCompletedSuccessfully { get {
string res = this.task.IsCompletedSuccessfully ? "" : "NOT";
return string.Format("task {0,3} completed {1} successfully", this.task.Id, res);
}
}
//任务执行信息
public string TotalResult
{
get
{
return string.Format("{0,3} times in {1,4} milliseconds total {2,4} miliseconds", this.Counter, this.TimeSpan, TotalTime);
}
}
//开启任务并返回任务ID
public int Start()
{
this.task.Start();
return this.task.Id;
}
public int TimeSpan { get => timeSpan; set => timeSpan = value; }//任务执行时间
public int Counter { get; set; } = 0; //任务执行次数
public int TotalTime { get => this.TimeSpan * this.Counter; } //总时间
}
}
任务管理者类ManagerJob.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp1.app.classes
{
delegate void AddMessageDelegate();//声明添加消息委托
class ManagerJob
{
const int TIME_SPAN_MIN = 10;
const int TIME_SPAN_MAX = 1000;
const int TIME_TO_SUPPLIER_DATA = 1000; //添加信息数据时间
public static AddMessageDelegate addMessage; //声明一个事件,委托类型
private static EventWaitHandle waitHandleStartJob = new AutoResetEvent(true); //等待开始事件 true设置初始状态为有信号;False设置初始状态为无信号。
private static EventWaitHandle waitHandleUpdateMessage = new AutoResetEvent(true);//等待更新消息事件
private Task manager;//管理者任务
private static Hashtable listJobs = new Hashtable();//哈希表:任务列表
public static StringBuilder payloadString = new StringBuilder();//有效载荷字符串
private static Queue<string> buffer = new Queue<string>();//字符串缓存队列:信息
private static bool trueToDO = true;//执行任务标记
private static int CountJobs { set; get; }//任务数
public ManagerJob(int countJobs)//构造函数:任务数
{
CountJobs = countJobs;
manager = new Task(ManagerTask);//管理者任务
}
/// <summary>
/// ManagerTask method to main task named ManagerTask
/// 1. Create work tasks.
/// 2. Read from queue buffer and run external code (addMessage()) to update data.
/// 3. Waiting for the end of work all tasks.
/// </summary>
private static void ManagerTask()
{
buffer.Enqueue("Manager task is started.");//消息队列
Random random = new Random();
for (int i = 0; i < CountJobs; i++)//创建带执行时间的任务,开启任务并加入任务列表。
{
int timeSpan = random.Next(TIME_SPAN_MIN, TIME_SPAN_MAX);
TaskJob job = new TaskJob(ToDoJob, timeSpan);//实例化TaskJob
listJobs.Add(job.Start(), job);//开启任务并加入任务列表: 任务id,TaskJob
}
//任务执行过程中,更新显示线程状态
while (CountJobs > 0)
{
Thread.Sleep(TIME_TO_SUPPLIER_DATA);//等待更新数据间隔
getData();//将消息队列中的信息显示到界面
}
//任务都执行完成后
foreach (DictionaryEntry pair in listJobs)
{
TaskJob job = (TaskJob)pair.Value;
buffer.Enqueue(string.Format("{0} {1}", job.IsCompletedSuccessfully, job.TotalResult));
}
buffer.Enqueue("Manager task finished work");
getData();//最后输出 任务完成信息
}
//显示buffer信息
private static void getData()
{
while (buffer.Count > 0)
{
payloadString.AppendFormat("{0}{1}", buffer.Dequeue(), Environment.NewLine);//取出缓存信息
}
addMessage();//触发添加消息事件
payloadString.Clear();
}
/// <summary>
/// ToDoJob method to tasks TaskJob
/// 1. To start job waiting to find job in class 'waitHandleStartJob.WaitOne();' first task(thread) into
/// 2. job(sleep)
/// 3. white to update data 'waitHandleUpdateMessage.WaitOne();'
/// </summary>
private static void ToDoJob()//任务动作
{
do
{
//第一个任务进入代码,其他任务等待 First task enter to code. The others are waiting.
waitHandleStartJob.WaitOne();//两个线程共享相同的AutoResetEvent对象,线程可以通过调用AutoResetEvent对象的WaitOne()方法进入等待状态,然后另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。
TaskJob jobStarted = null;
if (listJobs.ContainsKey(Task.CurrentId))
{
jobStarted = (TaskJob)listJobs[Task.CurrentId];//获取开启的TaskJob对象
}
else
{
break;
}
jobStarted.Counter++; //在timeSpan*n()时间内,切换执行当前Task的次数。
// 第一个任务切换waitHandleStartJob进入下一个线程。 First task switch waitHandleStartJob to enter next thread.
waitHandleStartJob.Set();//另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。
// Job (all tasks sleep time is defined in the constructor)
Thread.Sleep(jobStarted.TimeSpan);
// 最先唤醒的任务进入编码Task which woke up first enter to code
waitHandleUpdateMessage.WaitOne();//线程可以通过调用AutoResetEvent对象的WaitOne()方法进入等待状态
TaskJob jobFinish = null;
if (listJobs.ContainsKey(Task.CurrentId))
{
jobFinish = (TaskJob)listJobs[Task.CurrentId];
}
else
{
break;
}
DateTime date = DateTime.Now;
buffer.Enqueue( string.Format("job number {0,3} completed job in {1:HH:mm:ss.fff} after {2,4} miliseconds (total {3,8}).", Task.CurrentId, date, jobFinish.TimeSpan, jobFinish.TotalTime));
//任务切换到下一个任务的waitHandleUpdateMessage。 Task switch waitHandleUpdateMessage to next task.
waitHandleUpdateMessage.Set();//另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。
//CountJobs--; //正在执行的总任务数--
//return;
//取消以下注释,每个任务只执行一次。执行完毕后需手动停止管理者任务。
//增加以下代码
//CountJobs--; //正在执行的总任务数--
//while (trueToDO)
//{
// Thread.Sleep(100);
// //判断所有任务执行完毕,自动结束管理者任务
// if (CountJobs == 0)
// {
// trueToDO = false;
// }
//}
} while (trueToDO);
CountJobs--; //正在执行的总任务数--
}
public void Start()
{
this.manager.Start();
}
public void Stop()
{
// boolen var trueToDO = false => means stop infinite loop for TaskJob tasks
trueToDO = false;
}
}
}
单击“start”之后,单击“stop”执行结果:
取消注释后,单击“start”执行结果:执行一次任务后自动停止。有失败的任务。
// 取消以下注释,每个任务只执行一次。执行完毕后需手动停止管理者任务。
//增加以下代码
CountJobs--; //正在执行的总任务数--
while (trueToDO)
{
Thread.Sleep(10);//100 改成1000 所有任务都失败. 改成10任务都成功。
//判断所有任务执行完毕,自动结束管理者任务
if (CountJobs == 0)
{
trueToDO = false;
}
}
修改为如下之后,每个任务执行一次,都执行成功,速度快:
The End