- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 Stream 对象,我正在使用 BeginRead 开始(显然)读入缓冲区;读取完成后调用 AsyncCallback 函数。在此函数中,我可以检查用户是否想要获取下一个“ block ”并再次启动 BeginRead 进程。
我遇到的问题是用户可能会在流仍在读取时选择取消(因此在调用 AsyncCallback 函数之前),那么如何取消流的读取?
只是为了进一步解释这个问题 - 如果我将 BackgroundWorker 与 Streams Read 方法或异步 BeginRead 方法一起使用,我似乎会得到相同的结果。在我检查流是否应停止读取之前,用户可能需要等待 Read/BeginRead 方法完成的任意时间长度。
编辑: 下面的代码应该可以完成这项工作,我距离在 C# 中成为任何体面的东西还有一百万英里,所以它很可能有几个错误,因为我怀疑它是否完美,尽管它确实展示了解决方案。
简而言之,CWorkManager 管理一定数量的线程(这些线程保存在 CWorkerDetail 类中)。每个 CWorkerDetail 都有一个状态,可以是 EWaiting 表示工作人员可以启动,EReading 表示工作人员正在从源读取,在此期间可以立即停止工作人员,EWriting 将读取的数据保存到磁盘 -这不能立即停止,这个过程必须在线程停止之前完成。最后还有 EAborting,它由管理者设置,如果 worker 应该尽快中止;现在,只有当工作人员正在进行无法中断的事情(例如写入磁盘)时才会设置。
现在,实际上没有任何读取或写入正在进行,因为这只会使主要解决方案复杂化(基本上只是 StopWorker 函数检查 CWorker 的标志以查看它是否可以立即中止);因此,我们只是让线程休眠。
GUI 端非常简单,只有一个列表框(显示每个工作人员的状态)和一个停止和启动按钮。所有代码都在下面,希望这对某人有所帮助,但正如我所说,我对 C# 并不擅长,所以请注意错误等...
CWorkManager.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ThreadApplication {
//A worker that spawns a number of threads (managed internally) that does nothing useful at all.
public class CWorkManager {
//The status of the worker.
public enum EWorkerStatus {
EWaiting,
EReading,
EWriting,
EAborting,
}
//Holds all data relevant to the worker.
private class CWorkerDetails {
//Simple variables.
private readonly Object _Lock=new Object();
private Thread gThread;
private EWorkerStatus gStatus;
private CWorkManager gParentInstance;
private int gIndex;
//Simple constructor.
public CWorkerDetails(int aIndex, CWorkManager aParentInstance, Thread aThread, EWorkerStatus aStatus) {
gIndex=aIndex;
gParentInstance=aParentInstance;
gThread=aThread;
gStatus=aStatus;
}
//Simple get set methods.
public Thread GetThread() { lock(_Lock) { return gThread; } }
public EWorkerStatus GetStatus() { lock(_Lock) { return gStatus; } }
//Sets the status and automatically updates the GUI.
public void SetStatus(EWorkerStatus aStatus) {
lock(_Lock) {
gStatus=aStatus;
Form1.gInstance.Invoke(new UpdateGUIDelegate(gParentInstance.UpdateGUI), new object[] { gIndex, GetStatus() });
}
}
}
//Worker variable.
private List<CWorkerDetails> gWorkers;
//Simple constructor.
public CWorkManager(int aWorkerCount){
gWorkers=new List<CWorkerDetails>();
for(int tIndex=0; tIndex<aWorkerCount; tIndex++)
gWorkers.Add(null);
}
//Creates and starts the worker.
public void StartWorker(int aWorkerIndex) {
//Create a new worker if there is none or if it is waiting to start.
if(gWorkers.ElementAt(aWorkerIndex)==null||gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
gWorkers[aWorkerIndex]=new CWorkerDetails(aWorkerIndex, this, new Thread(new ParameterizedThreadStart(WorkerMethod)), EWorkerStatus.EWaiting);
//If the worker is waiting to start, then start.
if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
gWorkers.ElementAt(aWorkerIndex).GetThread().Start(gWorkers.ElementAt(aWorkerIndex));
}
//Stops the worker.
public void StopWorker(int aWorkerIndex) {
//Do nothing if the worker is null.
if(gWorkers.ElementAt(aWorkerIndex)==null)
return;
//Do nothing if the worker is waiting.
if(gWorkers.ElementAt(aWorkerIndex).GetStatus()==EWorkerStatus.EWaiting)
return;
//If the worker is reading we can abort instantly.
if(gWorkers[aWorkerIndex].GetStatus()==EWorkerStatus.EReading) {
gWorkers[aWorkerIndex].GetThread().Abort();
gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EWaiting);
return;
}
//Since the worker is not reading or waiting, we have to request the
//worker to abort by itself.
gWorkers[aWorkerIndex].SetStatus(EWorkerStatus.EAborting);
}
//Updates the GUI.
private delegate void UpdateGUIDelegate(int aIndex, EWorkerStatus aStatus);
private void UpdateGUI(int aIndex, EWorkerStatus aStatus) {
Form1.gInstance.SetThreadStatus(aIndex, aStatus);
}
//This method is where all the real work happens.
private void WorkerMethod(Object aWorker) {
//Fetch worker.
CWorkerDetails mWorker=(CWorkerDetails)aWorker;
//Loop forever, the thread will exit itself when required.
while(true) {
//Is the worker status aborting - if so we stop here.
if(mWorker.GetStatus()==EWorkerStatus.EAborting) {
mWorker.SetStatus(EWorkerStatus.EWaiting);
return;
}
//This would normally be reading from a stream which would cause the thread
//to block, simulate this by just sleeping the thread.
mWorker.SetStatus(EWorkerStatus.EReading);
Thread.Sleep(3000);
//Is the worker status aborting - if so we stop here.
if(mWorker.GetStatus()==EWorkerStatus.EAborting) {
mWorker.SetStatus(EWorkerStatus.EWaiting);
return;
}
//All data has been read, set status to writing and again simulate by
//sleeping the thread.
mWorker.SetStatus(EWorkerStatus.EWriting);
Thread.Sleep(3000);
}
}
}
}
Form1.cs:
包含:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace ThreadApplication {
public partial class Form1:Form {
public static Form1 gInstance;
private CWorkManager gManager;
public Form1() {
InitializeComponent();
Button_Start.Click+=new EventHandler(Button_Start_Click);
Button_Stop.Click+=new EventHandler(Button_Stop_Click);
gInstance=this;
for(int tIndex=0; tIndex<5; tIndex++)
ListBox_WorkerStatus.Items.Add("Created");
gManager=new CWorkManager(ListBox_WorkerStatus.Items.Count);
}
public void SetThreadStatus(int aIndex, CWorkManager.EWorkerStatus aStatus) {
ListBox_WorkerStatus.Items[aIndex]=aStatus.ToString();
}
private void Button_Start_Click(object sender, EventArgs e) {
if(ListBox_WorkerStatus.SelectedIndex>=0) {
gManager.StartWorker(ListBox_WorkerStatus.SelectedIndex);
}
}
private void Button_Stop_Click(object sender, EventArgs e) {
if(ListBox_WorkerStatus.SelectedIndex>=0) {
gManager.StopWorker(ListBox_WorkerStatus.SelectedIndex);
}
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e) {
for(int tIndex=0; tIndex<ListBox_WorkerStatus.Items.Count; tIndex++) {
gManager.StopWorker(tIndex);
}
}
}
}
最佳答案
请看Cancel BeginRead这个
关于c# - 在 AsyncCallback 函数之外停止异步流,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6321733/
C语言sscanf()函数:从字符串中读取指定格式的数据 头文件: ?
最近,我有一个关于工作预评估的问题,即使查询了每个功能的工作原理,我也不知道如何解决。这是一个伪代码。 下面是一个名为foo()的函数,该函数将被传递一个值并返回一个值。如果将以下值传递给foo函数,
CStr 函数 返回表达式,该表达式已被转换为 String 子类型的 Variant。 CStr(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CSng 函数 返回表达式,该表达式已被转换为 Single 子类型的 Variant。 CSng(expression) expression 参数是任意有效的表达式。 说明 通常,可
CreateObject 函数 创建并返回对 Automation 对象的引用。 CreateObject(servername.typename [, location]) 参数 serv
Cos 函数 返回某个角的余弦值。 Cos(number) number 参数可以是任何将某个角表示为弧度的有效数值表达式。 说明 Cos 函数取某个角并返回直角三角形两边的比值。此比值是
CLng 函数 返回表达式,此表达式已被转换为 Long 子类型的 Variant。 CLng(expression) expression 参数是任意有效的表达式。 说明 通常,您可以使
CInt 函数 返回表达式,此表达式已被转换为 Integer 子类型的 Variant。 CInt(expression) expression 参数是任意有效的表达式。 说明 通常,可
Chr 函数 返回与指定的 ANSI 字符代码相对应的字符。 Chr(charcode) charcode 参数是可以标识字符的数字。 说明 从 0 到 31 的数字表示标准的不可打印的
CDbl 函数 返回表达式,此表达式已被转换为 Double 子类型的 Variant。 CDbl(expression) expression 参数是任意有效的表达式。 说明 通常,您可
CDate 函数 返回表达式,此表达式已被转换为 Date 子类型的 Variant。 CDate(date) date 参数是任意有效的日期表达式。 说明 IsDate 函数用于判断 d
CCur 函数 返回表达式,此表达式已被转换为 Currency 子类型的 Variant。 CCur(expression) expression 参数是任意有效的表达式。 说明 通常,
CByte 函数 返回表达式,此表达式已被转换为 Byte 子类型的 Variant。 CByte(expression) expression 参数是任意有效的表达式。 说明 通常,可以
CBool 函数 返回表达式,此表达式已转换为 Boolean 子类型的 Variant。 CBool(expression) expression 是任意有效的表达式。 说明 如果 ex
Atn 函数 返回数值的反正切值。 Atn(number) number 参数可以是任意有效的数值表达式。 说明 Atn 函数计算直角三角形两个边的比值 (number) 并返回对应角的弧
Asc 函数 返回与字符串的第一个字母对应的 ANSI 字符代码。 Asc(string) string 参数是任意有效的字符串表达式。如果 string 参数未包含字符,则将发生运行时错误。
Array 函数 返回包含数组的 Variant。 Array(arglist) arglist 参数是赋给包含在 Variant 中的数组元素的值的列表(用逗号分隔)。如果没有指定此参数,则
Abs 函数 返回数字的绝对值。 Abs(number) number 参数可以是任意有效的数值表达式。如果 number 包含 Null,则返回 Null;如果是未初始化变量,则返回 0。
FormatPercent 函数 返回表达式,此表达式已被格式化为尾随有 % 符号的百分比(乘以 100 )。 FormatPercent(expression[,NumDigitsAfterD
FormatNumber 函数 返回表达式,此表达式已被格式化为数值。 FormatNumber( expression [,NumDigitsAfterDecimal [,Inc
我是一名优秀的程序员,十分优秀!