2

スレッドでセマフォを使用する際に問題があります。これが私の状況です。現在の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から来ていると思います。そうすることで、実際には、スリープ呼び出しによってブロックされているメインスレッドでProcessmeコードを実行していることになります。

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 に答える