C#多线程问题 [英] C# multithreading problem

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

问题描述

你好,
我编写了一个程序,该程序将进行无人值守的SQL Server安装.我有一个主要形式和许多方法,这些方法以自上而下的方式开始.看起来像是:收集数据并检查它们,SQL Server安装,安装脚本,安装Service Pack,安装脚本等.我想通知用户程序的进度(例如,带有进度栏).首先,我尝试使用BackgroundWorker,它可以很好地工作,但是Worker不等待(或者我应该说:我不知道如何让它等待)完成前面的方法–我真正需要的是(在仍未安装SQL Server的情况下安装Service Pack是没有意义的.我已经找到了有关Jon Skeet网站解决方案的建议(

Hello,
I write a program that shall make an unattended SQL servers installation. There is a main form and many methods which I start in a top-down manner. It looks like that: collecting data and checking them, SQL servers install, install scripts, install service pack, install scripts etc. I would like to inform the user about the progress of the program (e.g. with progress bar). First I tried to work with BackgroundWorker, it works well but the Worker doesn’t wait (or should I say: I don’t know how to make it wait) for the previous method to be finished – what I actually need (there is no sense in installing Service Pack while the SQL Server is still not installed. I have found a proposal for solution of Jon Skeet site (http://www.yoda.arachsys.com/csharp/threads/winforms.shtml[^].). And used it in that way (here just one method: copy some data from drive A to drive B, after copying I should start SQL-Server installation, Service Pack etc.):

private void button1_Click(object sender, EventArgs e)
        {
            SQLInstallation inst = new SQLInstallation();

            inst.LWCopy(ref myAl, "C:\\ABC", "C:\\BDC");

            pBar1.Visible = true;
            pBar1.Minimum = 0;
            pBar1.Maximum = myAl.Count;
            pBar1.Value = 1;
            pBar1.Step = 1;

            lock (stateLock)
            {
                target = myAl.Count;
            }
            Thread t = new Thread(new ThreadStart(ThreadJob));
            t.IsBackground = true;
            t.Start();
            
        }

        

        void ThreadJob()
        {
            Object[] jajco = myAl.ToArray();
            
            
            MethodInvoker updateCounterDelegate = new MethodInvoker(UpdateCount);
            int localTarget;
            lock (stateLock)
            {
                localTarget = target;
            }
            UpdateStatus("Installationsdateien kopieren.");
            lock (stateLock)
            {
                currentCount = 0;
            }
            Invoke(updateCounterDelegate);
            // Pause before starting
            Thread.Sleep(50);
            UpdateStatus("Counting");

            for (int i = 0; i < localTarget; i++)
            {
                lock (stateLock)
                {
                    string input = jajco[i].ToString().Substring(0, jajco[i].ToString().IndexOf(","));
                    string target = jajco[i].ToString().Substring(jajco[i].ToString().IndexOf(",") + 1);
                    File.Copy(input, target, true);
                    //pBar1.PerformStep();
                    currentCount = i;
                    strAnzeige = target;
                }
                // Synchronously show the counter
                Invoke(updateCounterDelegate);
                Thread.Sleep(50);
            }
            UpdateStatus("Finished");
            //Invoke(new MethodInvoker(EnableButton));
            myAl = null;
            jajco = null;

        }

        void UpdateStatus(string value)
        {
            if (InvokeRequired)
            {
                // We're not in the UI thread, so we need to call BeginInvoke
                BeginInvoke(new StringParameterDelegate(UpdateStatus), new object[] { value });
                return;
            }
            // Must be on the UI thread if we've got this far
            lblStatus.Text = value;
        }

        void UpdateCount()
        {
            int tmpCount;
            lock (stateLock)
            {
                tmpCount = currentCount;
            }
            pBar1.Value = tmpCount;
            lblStatus.Text = "Coping..: " + strAnzeige;
        }




这是解决方案还是应该尝试解决写队列的问题?
帮助将不胜感激...
谢谢
Andy




Is this the solution or shall try to solve the problem writing a queue?
A help would be appreciate...
Thanks
Andy

推荐答案

我认为您错过了使用线程的要点.线程用于并行执行(或多或少)代码.您正在尝试再次同步线程,这引发了一个问题,为什么您完全使用线程.如果您成功按照所需的方式同步了它们,那么就好像您根本没有使用线程一样.那么,为什么要花时间和精力来完全设置线程?

线程当然将有助于保持用户界面的响应性,因此您可能需要保留它们.但是,为什么不简单地以表格的形式确保启动线程的按钮已按顺序启用.或一个接一个地启动线程而没有任何按钮.该表单可以使用IsAlive属性检查当前正在运行的线程的状态.
I think you miss the point in using threads. Threads are used to execute code in parallel (more or less). You are trying to synchronize the threads again, which raises the question why you use threads at all. If you succeed in synchronizing them the way you want, then it will be as if you did not use threads at all. So why put time and effort into setting up threads at all?

The threads will of course help to keep the user interface responsive, so you may want to keep them. But why don''t you simply make sure in your form that the buttons to start the threads are enabled in sequence. Or start the threads one after another without any buttons. The form can check the status of the currently running thread with the IsAlive property.


您好,
谢谢您的回答.没错:多线程对我来说是很新的...
可能我应该使用完全不同的东西.那我该如何解决我的问题呢?
1.有一个主要形式和一个按钮,自上而下开始许多方法
2.当然,问题在于我的应用程序是单线程的,因此当线程正在执行某些操作(复制文件,安装SQL Server等)时,它也无法绘制UI.
但是我将通知用户发生了什么,主要形式是冻结",并且看起来程序已崩溃.因此有几个思路的想法.
安迪
Hello,
thank you for your answer. It''s correct: multithreads are quite new to me...
It can be that I should use something completely different. So how shall I solve my problem?
1. there is a main form and a button starting many methods top-down
2. The problem, of course, is that my application is single-threaded, so while the thread is doing something (copying files, installing SQL Server etc.), it can''t also be drawing the UI.
But I will to inform the user what''s going on, the main form is "frozen" and it looks like the program were crashed. Therefore the idea with several thread.
Andy


hm,把这些东西放在一起对我来说是个大问题.
如何依次启动线程?
假设我以这种方式托盘:

< pre>
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Text;
使用System.Threading;

命名空间线程
{
公共类工作者
{
//线程启动时将调用此方法.
公共无效DoWork1()
{
而(!_shouldStop)
{
Console.WriteLine("worker1 thread:working ...");
}
Console.WriteLine("worker1线程:正常终止.");
}

公共无效DoWork2()
{
而(!_shouldStop)
{
Console.WriteLine("worker2 thread:working ...");
}
Console.WriteLine("worker2线程:正常终止.");
}

公共无效DoWork3()
{
而(!_shouldStop)
{
Console.WriteLine("worker3 thread:working ...");
}
Console.WriteLine("worker3线程:正常终止.");
}
公共无效RequestStop()
{
_shouldStop = true;
}
//Volatile用作向编译器提示此数据
//成员将被多个线程访问.
私人易失性布尔值_shouldStop;
}

公共类WorkerThreadExample
{
静态void Main()
{
Worker workerObject =新Worker();
RunThread(new Thread(workerObject.DoWork1));
RunThread(new Thread(workerObject.DoWork2));
RunThread(new Thread(workerObject.DoWork3));
}

公共静态无效RunThread(Thread ThreadInstance)
{
if(ThreadInstance!= null)
{
ThreadInstance.Start();
while(!ThreadInstance.IsAlive);
Thread.Sleep(1000);
workerObject.RequestStop();
ThreadInstance.Join();
}
}
}
}
</pre>

但这是不正确的,我得到的是:
worker1线程:正在工作...
worker1线程:正在工作...
主线程:启动工作线程...
worker3线程:正在工作...
worker3线程:正在工作...
worker3线程:正在工作...
worker3线程:正在工作...
worker3线程:正在工作...
worker3线程:正常终止.
worker1线程:正在工作...
worker1线程:正在工作...
worker1线程:正常终止.
worker2线程:正在工作...
worker2线程:正在工作...
worker2线程:正在工作...
worker2线程:正常终止.
主线程:工作线程已终止.

这意味着该序列运行错误:首先是一个线程1块,然后是3,然后是1,然后是2.我想要的是:线程1、2、3.
你能帮我吗?
hm, putting the things together is the big problem for me.
How to start the threads in sequence?
Let''s say I tray it in that way:

<pre>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Threading
{
public class Worker
{
// This method will be called when the thread is started.
public void DoWork1()
{
while (!_shouldStop)
{
Console.WriteLine("worker1 thread: working...");
}
Console.WriteLine("worker1 thread: terminating gracefully.");
}

public void DoWork2()
{
while (!_shouldStop)
{
Console.WriteLine("worker2 thread: working...");
}
Console.WriteLine("worker2 thread: terminating gracefully.");
}

public void DoWork3()
{
while (!_shouldStop)
{
Console.WriteLine("worker3 thread: working...");
}
Console.WriteLine("worker3 thread: terminating gracefully.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}

public class WorkerThreadExample
{
static void Main()
{
Worker workerObject = new Worker();
RunThread(new Thread(workerObject.DoWork1));
RunThread(new Thread(workerObject.DoWork2));
RunThread(new Thread(workerObject.DoWork3));
}

public static void RunThread(Thread ThreadInstance)
{
if(ThreadInstance != null)
{
ThreadInstance.Start();
while(!ThreadInstance.IsAlive);
Thread.Sleep(1000);
workerObject.RequestStop();
ThreadInstance.Join();
}
}
}
}
</pre>

But it''s not correct, what I get is:
worker1 thread: working...
worker1 thread: working...
main thread: Starting worker thread...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: working...
worker3 thread: terminating gracefully.
worker1 thread: working...
worker1 thread: working...
worker1 thread: terminating gracefully.
worker2 thread: working...
worker2 thread: working...
worker2 thread: working...
worker2 thread: terminating gracefully.
main thread: Worker thread has terminated.

what means, that the sequence run wrong: first a chunk of thread1, than 3 completly, then a chunk of 1, then 2. What I wanted was: thread 1, 2, 3.
Could you help me?


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

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