Vincent Dagpin
Vincent Dagpin

Reputation: 3611

Threading with Semaphore

I have a problem using Semaphore in threading.. this is my situation, i want to change the ListViewItem's background color at the current 3 threads then turns into another color after a certain time passess using PauseForMilliSeconds then release another thread after 1 is done so i can limit the maximum thread execution into 3 threads only but the problem is the application will not respond.

this is my code

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

any help or solution to my problem?

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

Upvotes: 2

Views: 2823

Answers (1)

Samy Arous
Samy Arous

Reputation: 6814

I think your problem comes from the Invoke which is misplaced. By doing so, you are actually executing the Process me code in the main thread which is blocked by the sleep call.

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

Upvotes: 3

Related Questions