2

我在线程中使用 Semaphore 时遇到问题.. 这是我的情况,我想在当前 3 个线程中更改ListViewItem的背景颜色,然后在使用PauseForMilliSeconds一段时间后变成另一种颜色,然后在 1 完成后释放另一个线程所以我可以将最大线程执行限制为 3 个线程,但问题是应用程序不会响应。

这是我的代码

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace _Sample__Using_Semaphore
{
public partial class frmMain : Form
{
    Semaphore semaphore = new Semaphore(0, 3);

    public frmMain()
    {
        InitializeComponent();
    }

    private void frmMain_Load(object sender, EventArgs e)
    {
        for (int i = 1; i <= 10; i++)
        {
            ListViewItem lvi = new ListViewItem(new string[] { i.ToString(), "Ready", "0" });
            lvItems.Items.Add(lvi);
        }
    }        

    private void btnStartStop_Click(object sender, EventArgs e)
    {
        semaphore.Release(3);

        for (int i = 0; i < lvItems.Items.Count; i++)
        {
            WorkerThread(i);
        }
    }

    private Thread WorkerThread(int startNum)
    {
        Thread t = new Thread(() => WorkerProcess(startNum));
        t.Start();

        return t;
    }

    private void WorkerProcess(int startNum)
    {
        Invoke((MethodInvoker)delegate()
        {
            ProcessMe(startNum);
        });
    }

    private void ProcessMe(int index)
    {
        Random rand = new Random();

        semaphore.WaitOne();

        lvItems.Items[index].BackColor = Color.Red;

        PauseForMilliSeconds(rand.Next(500, 5000));

        lvItems.Items[index].BackColor = Color.Yellow;

        semaphore.Release(1);
    }

    public DateTime PauseForMilliSeconds(int MilliSecondsToPauseFor)
    {
        DateTime ThisMoment = DateTime.Now;
        TimeSpan duration = new TimeSpan(0, 0, 0, 0, MilliSecondsToPauseFor);
        DateTime AfterWards = ThisMoment.Add(duration);

        while (AfterWards >= ThisMoment)
        {
            System.Windows.Forms.Application.DoEvents();
            ThisMoment = DateTime.Now;
        }

        return DateTime.Now;
    }
}
}

对我的问题有任何帮助或解决方案吗?

解决方案:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Threading;

namespace _Sample__Using_Semaphore
{
public partial class frmMain : Form
{
    Semaphore semaphore = new Semaphore(0, 3);

    public frmMain()
    {
        InitializeComponent();
    }

    private void frmMain_Load(object sender, EventArgs e)
    {
        for (int i = 1; i <= 10; i++)
        {               
            ListViewItem lvi = new ListViewItem(new string[] { i.ToString(), "Ready", "0" });
            lvItems.Items.Add(lvi);
        }
    }        

    private void btnStartStop_Click(object sender, EventArgs e)
    {
        semaphore.Release(3);

        foreach (ListViewItem lvi in lvItems.Items)
        {
            WorkerThread(lvi.Index);
        }            
    }

    private Thread WorkerThread(int startNum)
    {
        Thread t = new Thread(() => WorkerProcess(startNum));
        t.Start();

        return t;
    }

    private void WorkerProcess(int startNum)
    {
        ProcessMe(startNum);            
    }

    private void ProcessMe(int index)
    {
        Random rand = new Random();

        semaphore.WaitOne();

        Invoke((MethodInvoker)delegate()
        {
            lvItems.Items[index].BackColor = Color.Red;
        });           

        PauseForMilliSeconds(rand.Next(500, 5000));

        Invoke((MethodInvoker)delegate()
        {
            lvItems.Items[index].BackColor = Color.Yellow;
        });

        semaphore.Release(1);
    }

    public DateTime PauseForMilliSeconds(int MilliSecondsToPauseFor)
    {
        DateTime ThisMoment = DateTime.Now;
        TimeSpan duration = new TimeSpan(0, 0, 0, 0, MilliSecondsToPauseFor);
        DateTime AfterWards = ThisMoment.Add(duration);

        while (AfterWards >= ThisMoment)
        {
            System.Windows.Forms.Application.DoEvents();
            ThisMoment = DateTime.Now;
        }

        return DateTime.Now;
    }
}
}
4

1 回答 1

3

我认为您的问题来自放错位置的 Invoke。通过这样做,您实际上是在被睡眠调用阻塞的主线程中执行 Process me 代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{

    public partial class Form1 : Form
    {
        Semaphore semaphore = new Semaphore(0, 3);
        public Form1()
        {
            InitializeComponent();
            myDelegate = new ChangeBack(ChangeBackMethod); 
        }

         private void frmMain_Load(object sender, EventArgs e)
    {
        for (int i = 1; i <= 10; i++)
        {
            ListViewItem lvi = new ListViewItem(new string[] { i.ToString(), "Ready", "0" });
            lvItems.Items.Add(lvi);
        }
    }        

    private void btnStartStop_Click(object sender, EventArgs e)
    {
        semaphore.Release(3);

        for (int i = 0; i < lvItems.Items.Count; i++)
        {
            WorkerThread(i);
        }
    }

    private Thread WorkerThread(int startNum)
    {
        Thread t = new Thread(new ParameterizedThreadStart(WorkerProcess));
        t.Start(startNum);

        return t;
    }

    private void WorkerProcess(object startNum)
    {

            ProcessMe((int)startNum);

    }

    private void ProcessMe(int index)
    {
        Random rand = new Random();

        semaphore.WaitOne();


        lvItems.BeginInvoke(myDelegate, index, Color.Red);

        Thread.Sleep(rand.Next(500, 5000));

        lvItems.BeginInvoke(myDelegate, index, Color.Yellow);

        semaphore.Release();

    }
    public delegate void  ChangeBack(int index, Color c);
    private ChangeBack myDelegate;
    private void ChangeBackMethod(int index, Color c)
    {

        lvItems.BeginUpdate();
        ((ListViewItem)(lvItems.Items[index])).BackColor = c;
        lvItems.EndUpdate();
    }

    public DateTime PauseForMilliSeconds(int MilliSecondsToPauseFor)
    {
        DateTime ThisMoment = DateTime.Now;
        TimeSpan duration = new TimeSpan(0, 0, 0, 0, MilliSecondsToPauseFor);
        DateTime AfterWards = ThisMoment.Add(duration);

        while (AfterWards >= ThisMoment)
        {
            //System.Windows.Forms.Application.DoEvents();
            ThisMoment = DateTime.Now;
        }

        return DateTime.Now;
    }
    }
}
于 2012-05-16T17:31:56.533 回答