线程返回值的问题

时间:2013-07-27 11:38:25

标签: c# multithreading

我正在尝试启动一个线程,从中接收字符串,然后使用收到的字符串启动n个线程计数。代码:

private void button2_Click(object sender, EventArgs e)
{
    string post = null;
    sync = new ManualResetEvent(false);
    var thr = new Thread[1];
    thr[0] = new Thread(delegate() { post = create_note(); });
    thr[0].IsBackground = true;
    thr[0].Start();
    sync.WaitOne();
    decimal value = Program.Data.numericUpDown1;
    int i = 0;
    int j = (int)(value);
    thr = new Thread[j];
    for (; i < j; i++)
    {
       thr[i] = new Thread(() => invite(post)); 
       thr[i].IsBackground = true;
       thr[i].Start();
     }
}

public string create_note()
{
    while (true)
    {
        string acc = "";
        string proxy = "";
        if (Program.Data.checkBox1 || Program.Data.checkBox2)
        {
            if (Program.Data.checkBox1)
                Proxy.type = "http";
            else if (Program.Data.checkBox2)
                Proxy.type = "socks5";
            lock (locker)
            {
                if (Proxy.proxies.Count == 0)
                {
                    foreach (string prox in File.ReadAllLines(proxy_path))
                    {
                        if (prox.Contains(":"))
                            Proxy.proxies.Add(prox);
                    }
                }
            }
            proxy = rand_proxy();
        }
        else if (!Program.Data.checkBox1 && !Program.Data.checkBox2)
            Proxy.type = "none";
        if (edit_accs.Count == 0)
        {
            break;
        }
        else
            acc = edit_accs.Dequeue();
        Od_post od_post = new Od_post(acc, proxy, Proxy.type);
        string login = od_post.Auth();

        if ()
        {
            string url = rand_url();
            var text = new RandomString(Program.Data.textBox3).ToString();

            string wall_post_text = od_post.wall_post_text(get_text(text), url);
            if (wall_post_text == "Good")
            {

                string image_add = od_post.image_add(post_image_path);
                if (image_add.Split('|')[0] == "Good")
                {
                    if (Program.Data.checkBox5)
                    {
                        string change_name = od_post.change_name();
                        if (change_name == "Changed")
                        {                                        
                        }
                        else
                        {
                        } 
                    }
                    sync.Set();
                    return image_add.Split('|')[1];
                }
                else
                { 
                }
            }
            else
            {
            }
        }
        else
        {
            lock (locker)
            {
                accs.Enqueue(acc);
                Proxy.proxies.Remove(proxy);
            }  
        }
    }
    return "Failed";
}

但它不起作用。我的应用程序挂起,帖子没有收到create_note()的返回值。为什么呢?

1 个答案:

答案 0 :(得分:4)

thr[0].Start();
sync.WaitOne();

使用线程时这是一个非常常见的错误。线程可以给你带来两个好处。一个是代码可以同时运行,如果你有一台具有多个内核的机器,你可以完成更多的工作。更常见的是,它可以运行代码异步,这是您想要保持响应的用户界面时的一个考虑因素。

你们两个都没有。它不会同时运行,你的主线程没有做任何工作,因为它正在等待线程完成。并且它也不会异步运行,当线程正在执行其工作时,主线程被冻结。

您可以获得线程的所有缺点。经典的线程错误是“竞赛”,你的代码有一个。您希望在WaitOne()方法完成后分配“post”变量。它可能是,但可能性不是那么好。由于在之前调用Set(),因此执行赋值。只有在分配后调用Set()时,它才能正常工作。死锁是另一个经典的线程错误,我没有看到,但你的调试器可以很容易地告诉你。死锁很可能在这里,因为你冻结你的主线程。在线程上调用类似Invoke()的调用将会死锁。

你的代码有一个非常简单的替代品,可以完成你希望当前代码所做的一切,减去线程错误:

string post = create_note();

问题解决了。

Minus解决了您考虑首先编写此代码的原因。这要求您将WaitOne()调用之后的所有代码移动到线程完成时运行的回调。这样的代码往往难以编写,处理异步性并不容易。但是你可以从.NET获得帮助来实现这一点,例如BackgroundWorker.RunWorkerCompleted事件,Task类及其TaskScheduler.FromCurrentSynchronizationContext()方法。并且 async 关键字已添加到C#版本5中。