我必須從提供的DLL調用例程。該DLL需要2到10分鐘才能運行,具體取決於正在運行的PC的速度。一個後臺進程的兩個線程?
我已將DLL調用放入BackgroundWorker線程,以便界面保持響應。
private object Load(string feature) {
object result = null;
using (var w = new BackgroundWorker()) {
w.WorkerReportsProgress = true;
w.WorkerSupportsCancellation = true;
w.DoWork += delegate(object sender, DoWorkEventArgs e) {
e.Result = DAL.get(feature);
};
w.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
progressBar1.Visible = false;
if (e.Error != null) {
MessageBox.Show(this, e.Error.Message, "Load Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} else {
result = e.Result;
}
};
w.RunWorkerAsync();
if (w.IsBusy) {
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = true;
}
}
return result;
}
這工作,但我不能打電話與正在等待其結果的其他調用此方法,因爲內嵌它會立即返回空值。
所以,我被困在一個ManualResetEvent的實例,試圖讓該方法等待,直到它實際上是在返回前有一個值:
private object Load(string feature) {
object result = null;
using (var w = new BackgroundWorker()) {
var mre = new ManualResetEvent(false);
w.WorkerReportsProgress = true;
w.WorkerSupportsCancellation = true;
w.DoWork += delegate(object sender, DoWorkEventArgs e) {
e.Result = DAL.get(feature);
};
w.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) {
progressBar1.Visible = false;
if (e.Error != null) {
MessageBox.Show(this, e.Error.Message, "Model Load Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
} else {
result = e.Result;
}
mre.Set();
};
w.RunWorkerAsync();
if (w.IsBusy) {
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Visible = true;
progressBar1.Value = 0;
const string statusRun = @"\|/-";
const string statusMsg = "Loading Data...";
int loops = 0;
do {
int index = loops++ % 4;
tsStatus.Text = statusMsg + statusRun[index].ToString(); // '\', '|', '/', '-'
} while (!mre.WaitOne(200));
}
}
return result;
}
但是,看來,這樣做會導致我所有的CPU時間花在ManualResetEvent的WaitOne
方法上,並且Set()
觸發器永遠不會被調用。
有沒有人遇到過這種行爲,並找到一個很好的解決方法呢?
我在過去爲它創建瞭解決方法,但它涉及創建第二個線程來運行WaitOne
方法,以便第一個線程可以處理DoWork
代碼。
*使用* BackgroundWorker存在問題嗎?我曾多次在多個項目中完成此任務,並且從未造成任何問題。 – jp2code
您在代碼中使用的方式沒問題,因爲在離開'使用'範圍時,工作人員已經完成了。這隻有在後臺工作者*在同一範圍內啓動並完成時才起作用(這基本上使得它的工作同步,但無論如何)。但是,如果您按照我的建議將代碼分解爲兩部分,則無法使用。工作完成後,您必須手動調用Dispose。 – dialer
如果你確實使用'async',你可以簡化大部分代碼到'var result = await Task.Run((=)=> DAL.get(feature));' –