1

我正在尝试启动一个线程,从中接收字符串,然后使用接收到的字符串启动 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(). 为什么?

4

1 回答 1

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

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

你什么都得不到。它不会同时运行,您的主线程没有做任何工作,因为它正在等待线程完成。而且它也不是异步运行的,您的主线程在线程执行其工作时被冻结。

相反,您会得到线程的所有缺点。一个经典的线程错误是一个“竞赛”,你的代码有一个。您希望在 WaitOne() 方法完成后分配“post”变量。可能是这样,但可能性并不大。由于您在分配执行之前调用 Set() 。只有在赋值调用 Set() 才能正常工作。死锁是另一个经典的线程错误,我没有看到,但您的调试器可以轻松地向您展示。这里很可能出现死锁,因为您正在冻结主线程。在线程上进行像 Invoke() 这样的调用将会死锁。

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

string post = create_note();

问题解决了。

减去首先考虑编写此代码的原因。这确实需要您将 WaitOne() 调用之后的所有代码移动到线程完成时运行的回调中。这样的代码往往很难编写,处理异步并不是那么容易。但是您可以从 .NET 获得帮助来正确处理此问题,例如 BackgroundWorker.RunWorkerCompleted 事件、具有 TaskScheduler.FromCurrentSynchronizationContext() 方法的 Task 类。并且在 C# 版本 5 中添加了async关键字。

于 2013-07-27T12:23:34.857 回答