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