使用信号量进行线程处理

时间:2012-05-16 16:57:11

标签: c# threadpool

我在线程中使用Semaphore时遇到问题..这是我的情况,我想在当前的3个线程中更改 ListViewItem 的背景颜色,然后在一段时间之后变成另一种颜色passess使用 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;
    }
}
}

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

SOLUTION:

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;
    }
}
}

1 个答案:

答案 0 :(得分: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;
    }
    }
}