我正在研究别人的代码,并且没有太多与多线程有关的经验.我遇到了这行代码:
BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });
我想知道为什么这样做会有效: btnCalibrate.PerformClick();
谢谢你的回答.
我正在研究一个数据绑定很大的Win.Forms应用程序,我发现了一些奇怪的行为.该应用程序具有单独的I/O线程,通过异步Web请求接收更新,然后将其发送到主/ GUI线程以处理和更新应用程序范围的数据存储(这些数据存储又可能与各种GUI元素绑定数据)等).Web请求另一端的服务器需要定期请求或会话超时.
我已经经历了几个处理线程问题等的尝试解决方案,并且我观察到以下行为:
如果我使用Control.Invoke将更新从I/O线程发送到主线程,并且此更新导致显示MessageBox,则主窗体的消息泵将停止,直到用户单击ok按钮.这也会阻止I/O线程继续最终导致服务器超时.
如果我使用Control.BeginInvoke从I/O线程(或多个)发送更新主线程的主窗体的消息泵并没有停止,但如果一个更新的处理导致了一个消息被显示,其余的处理在用户单击"确定"之前,该更新将暂停.由于I/O线程继续运行并且消息泵继续处理消息,因此可以在具有消息框的那个之前调用几个BeginInvoke用于更新.这导致无序更新,这是不可接受的.
I/O线程向阻塞队列添加更新(非常类似于在.NET中创建阻塞队列<T>).GUI线程使用Forms.Timer定期应用阻塞队列中的所有更新.此解决方案解决了阻塞I/O线程和更新顺序的问题,即下一次更新将永远不会开始,直到上一次完成.但是,性能成本较低,并且在显示更新方面存在延迟,从长远来看这是不可接受的.我希望主线程中的更新处理是事件驱动而不是轮询.
所以对我的问题.我应该怎么做到:
更新:见下面的解决方案
我正在开发的一个c#应用程序主要包括对来自摄像头的图像执行操作并将其打印在图片框上.它有一个用c ++编写的库,它从网络摄像头(imgcam)中检索图像,然后复制它们(imgcam_copy),然后将它们传送给请求它们的托管代码.反过来,应用程序的托管部分由一个辅助线程组成,该辅助线程执行一个while循环,该循环从非托管库中获取图像并将它们打印到图片框.
一切正常,一切都是最精致的部分,即从非托管代码到托管代码的动态资源管理对我来说似乎很清楚,我知道我正在做什么(至少我希望如此),但问题在于编写使线程正常工作所需的代码.事实上,即使在浏览网页数小时之后,我仍有很多事情不清楚.
我不得不用UI线程打印图像,所以我必须依赖Invoke.
delegate void setImageCallback(Image img);
private void showFrame(Image img)
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame), img);
}
else
{
pboxCam.Image = img;
}
}
Run Code Online (Sandbox Code Playgroud)
我有很多问题:
1)调用昂贵的操作?我已经做了很多努力来减少主要操作在图像上的执行时间,在显示结果时浪费部分收益会令人失望.
2)您是否认为同步使用Invoke或异步BeginInvoke +图像副本更好?
3)将Image作为函数参数但是作为类的成员访问它是否有帮助?
private delegate void setImageCallback();
private void showFrame()
{
if (pboxCam.InvokeRequired)
{
this.Invoke(new setImageCallback(showFrame));
}
else
{
pboxCam.Image = cm.bitmap;
}
}
Run Code Online (Sandbox Code Playgroud)
4)也许你不会分享我对性能的担心,但我想知道你是否分享了线程安全性.UI线程只是想在非UI线程复制它时显示图像,依赖异步机制真的不安全吗?
我有一个带有StartProcessing()方法的异步类,int ResultReady()它在完成处理时引发一个事件.StartProcessing()花很少的时间.
我想同步调用这个类.我的伪代码应该是这样的:
调用StartProcessing()
等待/睡眠,直到结果准备好
返回结果
什么设计模式最适合这个?你能指点我一个代码示例吗?
我试图通过将数据加载部分放入后台线程而不是在页面加载时在前台运行来使WP7应用程序中的页面UI更具响应性.
线程代码基本上通过一些数据工作,并将项添加到可观察集合中; 为了避免异常问题,我执行以下操作:
Deployment.Current.Dispatcher.BeginInvoke(() => { _events.Add(_newItem); });
Run Code Online (Sandbox Code Playgroud)
以便在UI线程中将项添加到集合中.
我现在遇到的问题是代码的后续部分需要对集合执行foreach,以便找出插入新项目的位置而不是仅添加它.不幸的是,我发现的是,当我处于foreach循环中时,UI线程有时可以执行其Add,立即打破foreach.
从我已经完成的阅读开始,看起来一种方法是调用EndInvoke()以阻止后台线程,直到完成UI部分.不幸的是,看起来Wp7/Silverlight实现不支持EndInvoke.
有关如何在开始使用foreach之前检查添加是否已完成的任何建议?
谢谢.
菲利普
我正在尝试将当前的Express版本升级为Express with Advanced Services以支持全文搜索.
目前的系统设置是:
我已经下载了带有高级服务的SQL Server.我无法升级版本.安装步骤没有任何问题,甚至获得版本升级完成页面.但是一旦我点击关闭此页面,就会弹出一个错误.
SQL Server安装程序遇到以下错误:在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke.
有人可以帮助我到正确的方向吗?
我可以看到带有高级服务的SQL Server Express版本是10.50.1600.1.这是原因吗?那么在升级之前我应该将sp1降级到正常的Express r2版本吗?
带有高级服务的Express的下载链接http://www.microsoft.com/download/en/details.aspx?id=25174
我有一个apiClient.OrderSend必须在"GUI"线程内调用的函数,所以我创建了这个函数
private void RunOnUIThread(Action action)
{
this.BeginInvoke(action);
}
Run Code Online (Sandbox Code Playgroud)
然后,我有一个需要的功能return的int这样的
int AlgoSendOrder(MT4Order order)
{
int retVal = -1;
RunOnUIThread(() =>
{
retVal = apiClient.OrderSend(order.Symbol, (TradeOperation)order.OrderSide, order.Volume,
order.Price, order.AllowedSlippage ?? default(int),
order.PriceToStopLoss ?? default(double),
order.PriceToTakeProfit ?? default(double));
});
return retVal;
}
Run Code Online (Sandbox Code Playgroud)
问题是AlgoSendOrder返回之前apiClient.OrderSend返回,因此retVal对于此函数的客户端始终为-1.
看来这个合理的改变就是await-async在GUI线程中使用pair执行函数,并具有等待返回值的预期效果.但是我似乎无法让它发挥作用.
好像我应该可以返工RunOnUIThread使用async-await
public async Task RunOnUIThreadAsync()
{
if (InvokeRequired)
{
// what do I put here?
}
{
… // like before (but …Run Code Online (Sandbox Code Playgroud) 我需要让UI线程等待,直到任务数组完成执行.下面的代码的问题是 - 任务inturn调用UI线程写入文本框.如何解决这个问题?
public partial class FormConsole : Form
{
public FormConsole()
{
InitializeComponent();
}
void txtSayHello_Click(object sender, EventArgs e)
{
Class1 objclss = new Class1();
objclss.formConsole = this;
Task[] taa = new Task[4];
taa[0] = new Task(() => objclss.DoSomeThigs("Hello world"));
taa[1] = new Task(() => objclss.DoSomeThigs("Hello world1"));
taa[2] = new Task(() => objclss.DoSomeThigs("Hello world2"));
taa[3] = new Task(() => objclss.DoSomeThigs("Hello world3"));
foreach(Task task in taa)
{
task.Start();
}
Task.WhenAll(taa);
this.txtConsole.AppendText("All threads complete");
}
delegate void doStuffDelegate(string value);
public void …Run Code Online (Sandbox Code Playgroud) 我做了一个C#winforms应用程序.现在我有一个有很多按钮的表单,它调用了大量的数字运算函数,其输出我在文本框中更新.我调用textbox.begininvoke()方法,我将委托传递给更新文本框中文本的函数,但是当文本很大时,表单没有响应,因为我无法单击取消按钮.是不是有任何方式使整个表单保持响应,并且更新也不断发生.我必须向用户显示数据,因为它即将到来,我无法缓冲整个事情并最终显示.我还尝试实现自己的缓冲区并以特定的时间间隔显示数据,这对于少量文本很有用,但是大量的UI只是没有响应.任何帮助?谢谢
更新问题是因为出现了一些混淆
我对WPF比较陌生.我正在检查一些看起来像这样的代码:
private void button_Click(object sender, RoutedEventArgs e)
{
//Queue on dispatcher in the background so it doesn't make the UI slow
Dispatcher.BeginInvoke(new dMyDelegate(PerformOperation), DispatcherPriority.Background);
}
Run Code Online (Sandbox Code Playgroud)
从评论中,我猜测原始代码认为这对于使UI更具响应性是必要的,但是,我的理解是Dispatcher.BeginInvoke只是在UI线程上运行某些东西.由于buttn_Click已经在UI线程上,有什么意义呢?也许我误解了Dispatcher和BeginInvoke.在这种情况下,我假设Dispatcher是此方法所在的类所拥有的调度程序,即MainWindow.xaml.有人可以开导我吗?
谢谢
begininvoke ×10
c# ×7
.net ×3
invoke ×2
winforms ×2
async-await ×1
asynchronous ×1
controls ×1
delegates ×1
dispatcher ×1
messagebox ×1
task ×1
upgrade ×1
wpf ×1