以并行或并发方式向面板添加控件
本文关键字:添加 控件 方式 并行 并发 | 更新日期: 2023-09-27 18:17:22
有一个面板,我想添加k
控件到它。我想为每个控件指定任务,以便以后使用。所以:
*用一些其他代码更新下面的代码;请注意第三个代码*
*****Update*****
Child Control : PacketData (can be a Button)
Main Control : panel
PlaceData() changes the left and top randomly.
我必须这样做:
Parallel.For(0, k, (m) =>
{
tasks[m] = Task.Factory.StartNew(() =>
{
PacketData data = new PacketData();
data.StartTime = sw.ElapsedMilliseconds;
lock (data_adding_lock)
{
IAsyncResult iar = panel1.BeginInvoke(new MethodInvoker(()=>{
PlaceData(ref data);
panel1.Controls.Add(data);
}));
panel1.EndInvoke(iar);
while (iar.IsCompleted ==false ) ;
}
});
});
它有时很好,但有时不是,例如有时它只添加一个PacketData
到面板控制。我是否丢失了一个竞争条件?
我也试过这个,但不工作…
Parallel.For(0, k, (m) =>
{
tasks[m] = Task.Factory.StartNew(() =>
{
PacketData data;
lock (data_instancing_lock) {
data = new PacketData();}
data.StartTime = sw.ElapsedMilliseconds;
IAsyncResult iar = panel1.BeginInvoke(new MethodInvoker(()=>{
PlaceData(ref data);
lock(data_adder_lock){
panel1.Controls.Add(data);}
}));
panel1.EndInvoke(iar);
//PlaceData(ref data);
});
});
*更新* *
这里是另一个例子(它不工作…)
object l1 = new object();
object l2 = new object();
private delegate void AdderDel(Button bb);
public Form1()
{
InitializeComponent();
}
private void AddControl(Button x)
{
lock (l2)
{
this.Controls.Add(x);
}
}
private void Place(ref Button btn)
{
Random rnd = new Random();
int x = rnd.Next(0, this.Width-100);
int y = rnd.Next(0, this.Height-100);
btn.Left = x;
btn.Top = y;
}
private void button1_Click(object sender, EventArgs e)
{
int n = 5;
Task[] t = new Task[n];
AdderDel ad = new AdderDel(AddControl);
Parallel.For(0, n, (k) =>
{
t[k] = Task.Factory.StartNew(() =>
{
Button b = new Button();
b.Text = k.ToString();
b.Height = 50;
Place(ref b);
this.BeginInvoke(ad, b);
});
});
}
为什么?
你的代码太复杂了,特别是因为我没有看到在这里使用并行的任何优势。(虽然在实际代码中可能有一些原因,但很难从示例中看出。)我认为你不应该使用并行,直到你知道它是如何工作的。应该避免使用试错法编程,因为这意味着你并不真正理解你自己的代码,所以它会导致bug。
但是代码中的实际问题与并行性无关。这是你不正确地使用Random
。如果使用默认构造函数,Random
将以当前时间作为种子。这意味着,如果您像这样在短时间内连续创建多个Random
实例,它们都将返回相同的数字序列。这意味着所有的按钮都放置在表单上,除了它们都在同一个位置,所以您只能看到其中一个。
解决这个问题的最简单的方法是在一个字段中只有一个Random
实例,并且只能从UI线程访问它,或者在使用它时使用锁。
如果你的代码可以工作,你可以考虑把它发布到代码审查堆栈交换,让它得到审查,并解释你实际上试图做什么。