C# 启动异步任务而不等待它完成,但检查是否完成
我一直在努力寻找一个正确的答案,我发现要么太复杂,要么就是没有做我想要的。 情况很简单:C# 启动异步任务而不等待它完成,但检查是否完成,c#,winforms,C#,Winforms,我一直在努力寻找一个正确的答案,我发现要么太复杂,要么就是没有做我想要的。 情况很简单: 我想时不时地异步启动一个任务。同样的任务总是一样的。没有定义启动它的时间间隔(假设它是随机的) 该任务不接受任何参数,也不返回任何内容 我不想等它结束。它不能干扰程序的其余部分 我想在再次发射之前检查它是否完成。不希望同一任务同时运行多次。每次一个 我不想使用计时器或全局变量,比如信号量之类的。这只是一个简单问题的简单明了的解决方案 我尝试过背景工作,但任务重叠,因为我找不到可靠的方法来检查完成情况。我已尝
public Form1()
{
InitializeComponent();
//Instantiate each camera
//Subscribe to ProcessFrame1, ProcessFrame2 and ProcessFrame3
}
private void ProcessFrame1(object sender, EventArgs e)
{
if (captures[0] != null) //captures[0] is the handle for the camera 1
{
Mat snapshot = new Mat();
captures[0].Retrieve(snapshot);
if (snapshot != null)
{
frameCounter1++;
if (frameCounter1 > 5 && taskCompleted)
{
frameCounter1 = 0;
if (images[0] == null)
{
Image<Bgr, Byte> img = snapshot.ToImage<Bgr, Byte>();
images[0] = img.ToBitmap();
}
if (images[0] != null && images[1] != null && images[2] != null)
{
Thread hilo = new Thread(() => DetectFace());
hilo.IsBackground = true;
hilo.Start();
}
return;
}
else
imageBox1.Image = snapshot;
}
}
}
private void ProcessFrame2(object sender, EventArgs e)
{
if (captures[1] != null) //captures[1] is the handle for the camera 2
{
Mat snapshot = new Mat();
captures[1].Retrieve(snapshot);
if (snapshot != null)
{
frameCounter2++;
if (frameCounter2 > 5 && taskCompleted)
{
frameCounter2 = 0;
if (images[1] == null)
{
Image<Bgr, Byte> img = snapshot.ToImage<Bgr, Byte>();
images[1] = img.ToBitmap();
}
//I used to have the checking to fire up another DetectFace here
return;
}
else
imageBox2.Image = snapshot;
}
}
}
private void ProcessFrame3(object sender, EventArgs e) //Same as ProcessFrame2
private void DetectFace()
{
taskCompleted = false;
//Processing of Images
//Clear array of images
taskCompleted = true;
}
public Form1()
{
初始化组件();
//实例化每个摄像头
//订阅ProcessFrame1、ProcessFrame2和ProcessFrame3
}
私有void ProcessFrame1(对象发送方,事件参数e)
{
if(captures[0]!=null)//captures[0]是相机1的句柄
{
Mat快照=新Mat();
捕获[0]。检索(快照);
如果(快照!=null)
{
frameCounter1++;
如果(frameCounter1>5&&taskCompleted)
{
帧计数器1=0;
如果(图像[0]==null)
{
Image img=snapshot.ToImage();
images[0]=img.ToBitmap();
}
如果(图像[0]!=null和图像[1]!=null和图像[2]!=null)
{
线程hilo=新线程(()=>DetectFace());
hilo.IsBackground=true;
hilo.Start();
}
回来
}
其他的
imageBox1.Image=快照;
}
}
}
私有void ProcessFrame2(对象发送方,事件参数e)
{
if(captures[1]!=null)//captures[1]是照相机2的手柄
{
Mat快照=新Mat();
捕获[1]。检索(快照);
如果(快照!=null)
{
frameCounter2++;
如果(frameCounter2>5&&taskCompleted)
{
帧计数器2=0;
如果(图像[1]==null)
{
Image img=snapshot.ToImage();
images[1]=img.ToBitmap();
}
//我曾经有一张支票在这里点燃另一张侦探脸
回来
}
其他的
imageBox2.Image=快照;
}
}
}
private void ProcessFrame3(对象发送方,EventArgs e)//与ProcessFrame2相同
私有void DetectFace()
{
taskCompleted=false;
//图像处理
//清晰的图像阵列
taskCompleted=true;
}
任务使用状态,因此您可以随时启动任务、将引用保存在变量中并检查任务的当前状态
以下是有关任务不同状态的.NET文档:
遗憾的是,我现在不能给你一个代码示例,但我希望这个想法能有所帮助 我最终使用BlockingCollection实现了线程安全解决方案。感谢不信者@Damien_为我们指明了正确的方向 我认为这是在多线程环境中处理图像的一个重要教训。我了解到,在不同的线程中共享图像时,它们非常容易受到攻击 正如我在问题中所说,这里我必须从X个不同的网络摄像头中拍摄快照,在X个不同的图像框中显示它们,并尽可能快地(在不太中断所显示视频的fps的情况下)执行图像处理,而不是在图像框中显示帧。使用BlockingCollection,我不需要像以前那样(每5帧)确定处理帧的频率。现在我可以显示每个相机的帧,只要我已经将该相机的帧添加到BlockingCollection中 另一个需要注意的重要细节是,在BlockingCollection的.NET文档中,它说默认情况下它实现了FIFO,因为它是下层的ConcurrentQueue,但我认为这不是真的,因为我在实例化时必须自己定义它:
BlockingCollection<Tuple<int, Image>> tupleCollection = new BlockingCollection<Tuple<int, Image>>(new ConcurrentQueue<Tuple<int, Image>>(), X);
BlockingCollection tupleCollection=new BlockingCollection(new ConcurrentQueue(),X);
由于Take()方法无法针对集合中所需的元素,因此我必须使用元组来知道帧属于哪个摄影机,并按照定义ConcurrentQueue的顺序获取帧
所以基本上伪代码是这样的:
void Main()
{
//Instantiate cameras
//Subscribe to the ImageGrabbed events of each (producers)
// A simple blocking consumer with no cancellation.
Task.Run(() => DetectFace());
}
producer1(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == 1))
{
tupleCollection.Add(new Tuple<int, Image>(1, snapshot));
}
else
imageBox1.Image = snapshot;
}
producer2(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == 2))
{
tupleCollection.Add(new Tuple<int, Image>(2, snapshot));
}
else
imageBox2.Image = snapshot;
}
...
producerX(sender, e)
{
//Get snapshot
...
if (!tupleCollection.Any(x => x.Item1 == X))
{
tupleCollection.Add(new Tuple<int, Image>(X, snapshot));
}
else
imageBoxX.Image = snapshot;
}
private void DetectFace()
{
while (true)
{
Tuple<int, Image> data = null;
try
{
data = tupleCollection.Take();
}
catch (InvalidOperationException) { }
if (data != null)
{
//image processing
}
}
}
void Main()
{
//实例化摄影机
//订阅