同步线程的问题 [英] problem with synchronizing threads

查看:86
本文介绍了同步线程的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这里,我陷入了线程问题.

我创建了一个单击网页上按钮的功能,该功能会启动下载对话框(在浏览器控件内部).我在IE和下载"对话框中遇到了一个最令人沮丧的问题.似乎实际的下载文件"对话框是由Web浏览器在新线程中启动的.通常这很好,但事实证明,为下载而启动的新线程是同步启动的,因此,直到单击下载对话框上的按钮或对话框关闭(完成或取消)后,当前线程才会继续.

当我使用此代码时,主线程会暂停,直到新创建的线程停止为止.新线程尝试查找对话框窗口,该窗口将失败并停止.在此主线程恢复并显示对话框之后.

我无法同步此线程,不胜感激的任何帮助

Here I''m stuck in a problem with threading.

I have created one function which clicks button on web page which launches the download dialog box (inside browser control). I ran into a most frustrating issue with IE and the Download dialog. It seems that the actual "Download File" dialog is launched in a new thread by the web browser. While this would normally be fine, it turns out that the new thread launched for the the download is launched synchronously, so the current thread will not continue until a button on the download dialog is clicked, or the dialog closes (finished or cancelled).

When I use this code the main thread halts till the newly created threads stop. the new thread tries to find dialog window which is where it fails and it stops. After this main thread resumes and the dialog box appears.

I''m not able to synchronize this threads, any help greatly appreciated

public void DownloadFile()
        {
            HtmlElementCollection links = this.webBrowser1.Document.GetElementsByTagName("input");
            int btn = links.Count - 1;
            //links[btn].InvokeMember("Click"); 
            object btn1 = links[btn].DomElement;
            btn1.GetType().InvokeMember("click",System.Reflection.BindingFlags.InvokeMethod, null, btn1, null);
            Thread workThread = new Thread(delegate() { FindDownloadDialogWindow("#32770", "File Download", 25, @"D:\abc.zip"); });
            //wait until the dialog is found and file saved.
            workThread.Start();
            while (workThread.ThreadState != System.Threading.ThreadState.Stopped)
            {
                Thread.Sleep(1000);
                Application.DoEvents();
            } 
        }

推荐答案

非常非常糟糕的代码!

您启动线程;和线程旨在避免旋转等待,然后您使用旋转等待等待线程!哇,真是太可恶了!

1)永远不要旋转等待任何东西.

2)根据经验,切勿使用DoEvents,而应使用线程.

3)使用Thread.Join进行阻塞等待,直到线程结束.

4)不要创建您期望完成的线程.使用System.ComponentModel.BackgroundWorker.

5)不要通过非UI线程更新UI;而是使用System.Windows.Forms.Control.Invove;对于WPF和表单,请使用System.Threading.Dispatcher.Invoke.

您的代码无法修复,因此我无法告诉您正确的代码.为此,您应该更准确地说明您的最终目的.最有可能的是,您可以使用BackgroundWorker自己解决问题.

重要!不要发布答案,而应使用改善问题".这样,您可以放置​​格式化的代码.出于其他目的,请使用添加评论".

—SA
Very, very bad code!

You start thread; and thread are designed to avoid spin-wait, and then you use spin-wait to wait for the thread! Wow, what an abuse!

1) Don''t spin-wait for anything, ever.

2) As a rule of thumb, never use DoEvents, use a thread instead.

3) Use Thread.Join to for a blocking wait for the end of the thread.

4) Don not created threads which you expect to finish. Use System.ComponentModel.BackgroundWorker.

5) Do not update UI through non-UI thread; instead, use System.Windows.Forms.Control.Invove; for WPF and Forms, use System.Threading.Dispatcher.Invoke.

Your code is beyond repair, so I cannot tell you right code. To get this, you should explain your ultimate purpose more accurately. Most likely, you will be able to solve your problem yourself using BackgroundWorker.

Important! Do not post Answer, use "Improve Question" instead. In this way, you could put formatted code. For other purposes, use "Add Comment".

—SA


是的,一旦您想在单独的线程上执行操作,更好的选择是使用后台工作程序.因为它易于使用并且可以自己完成大部分工作.

它有三个事件,如下所述

yes dear, once you want to do things on separate threads, the better option is to use background worker. Because its easy to use and does most of the job itself.

There are three events of it, as described below

//This Event _DoWork Occurs on separate thread
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                 //implemen your download logic here

                 backgroundWorker1.ReportProgress(1);   //this is to report progress of your work
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message,"Download File");
            }
        }

// here you can access controls of main form or thread
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //you might want to show the download progres
            progressBar1.Increment(e.ProgressPercentage);
        }

// this event occours once your job is finished
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (checkBox_close.Checked)
            {                
                this.Close();
                this.Dispose();
            }
            label_size3.Text += " COMPLETED";
        }

//the Do work event is called from main thread or form like this

            backgroundWorker1.RunWorkerAsync();


就像我前段时间所承诺的那样,这是我对后续问题的回答.

如果方法DownloadFile应该重复多次,则方法应该大不相同.

您应该创建一个单独的线程并从头开始(如果更确切地说,在显示应用程序主窗体时,使用事件Shown).使用常规System.Threading.Thread.仅当将线程的输入数据馈送给线程时,线程才应保持睡眠和唤醒状态.这意味着您需要使用一些同步原语(我建议System.Threading.EventWaitHandleSystem.Threading.AutoResetEventSystem.Threading.ManualResetEvent).该线程正在等待对EventWaitHandle.WaitOne的调用,并在新任务准备就绪,完成整个周期(可能由于某些故障而异常)并返回时,从另一个线程(例如UI线程)调用EventWaitHandle.Set来唤醒该线程,在无限循环中重复下载周期.确保使用锁定在线程之间交换任务数据.

对于此特定任务,应使用更专门的工具:阻止消息队列.您的应用程序将下载任务队列(某些类型的封装URL,输出文件名和其他参数)放入下载线程;队列应处于阻塞状态,以避免旋转等待.

您可以在我的提示/技巧文章中找到经过充分测试的通用实现和用法示例:
As I promised a while ago, here is my answer to follow-up question.

If the method DownloadFile should be repeated many times, approach should be very different.

You should create a separate thread and start if from the very beginning (more exactly, when the application main form is shown, use the event Shown). Use regular System.Threading.Thread. The thread should be kept sleeping and wake up only when their input data is fed to them. It means you need to use some synchronization primitives (I would suggest System.Threading.EventWaitHandle, System.Threading.AutoResetEvent or System.Threading.ManualResetEvent). The thread is waiting at the call to EventWaitHandle.WaitOne and awakened by calling EventWaitHandle.Set from another thread (for example, UI thread) when new task is ready, complete full cycle (possibly with exception due to some failure) and comes back, repeating download cycle in infinite loop. Be sure to use locking for exchange of task data between thread.

For this particular task more specialized tool should be used: a blocking message queue. Your application makes a queue of download task (some type encapsulating URL, output file name and other parameters) which is fed to the downloading thread; the queue should be blocking, to avoid spin-wait.

You can find complete well tested generic implementation and usage sample in my Tips/Trick article: Simple Blocking Queue for Thread Communication and Inter-thread Invocation[^]. In the queue-based implementation, locking should not be used: the queue already provides propert synchronization.

The thread should notify the UI not directly (to show download status, etc.), but using Control.Invoke. This mechanism makes sure that UI properties/methods are not called by the non-UI thread but put to the queue, so actually calls are done in UI thread. By the way, my article referenced above provides pretty good explanation of how this invocation mechanism works.

Good luck,
—SA


这篇关于同步线程的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆