C# 仅执行一个线程

本文关键字:一个 线程 执行 | 更新日期: 2023-09-27 18:35:15

我有一个多线程应用程序。我只希望一个线程执行我的函数,而其他线程在我的函数执行时传递它。我该怎么做?

我的方法类似于:

    public void setOutput(int value)
    {
        try
        {
            GPOs gpos = reader.Config.GPO;
            gpos[1].PortState = GPOs.GPO_PORT_STATE.TRUE;
            gpos[2].PortState = GPOs.GPO_PORT_STATE.TRUE;
            Thread.Sleep(WAIT);
            gpos[1].PortState = GPOs.GPO_PORT_STATE.FALSE;
            gpos[2].PortState = GPOs.GPO_PORT_STATE.FALSE;
        }
        catch (Exception ex)
        {
            logger.Error("An Exception occure while setting GPO to " + value + " " + ex.Message);
        }
    }

C# 仅执行一个线程

您可以将锁定对象与 Monitor.TryEnter 结合使用。

private Object outputLock = new Object();
public void setOutput(int value)
{
    if Monitor.TryEnter(outputLock)
    {
        try
        {
            .... your code in here
        }
        finally
        {
            Monitor.Exit(outputLock);
        }
    }
}

一次只允许一个线程进入Monitor.TryEnter块。如果一个线程到达此处,而另一个线程在里面,则Monitor.TryEnter返回false

您可以使用互斥体

using System;
using System.Threading;
class Test
{
    // Create a new Mutex. The creating thread does not own the
    // Mutex.
    private static Mutex mut = new Mutex();
    private const int numIterations = 1;
    private const int numThreads = 3;
    static void Main()
    {
        // Create the threads that will use the protected resource.
        for(int i = 0; i < numThreads; i++)
        {
            Thread myThread = new Thread(new ThreadStart(MyThreadProc));
            myThread.Name = String.Format("Thread{0}", i + 1);
            myThread.Start();
        }
        // The main thread exits, but the application continues to
        // run until all foreground threads have exited.
    }
    private static void MyThreadProc()
    {
        for(int i = 0; i < numIterations; i++)
        {
            UseResource();
        }
    }
    // This method represents a resource that must be synchronized
    // so that only one thread at a time can enter.
    private static void UseResource()
    {
        // Wait until it is safe to enter.
        mut.WaitOne();
        Console.WriteLine("{0} has entered the protected area", 
            Thread.CurrentThread.Name);
        // Place code to access non-reentrant resources here.
        // Simulate some work.
        Thread.Sleep(500);
        Console.WriteLine("{0} is leaving the protected area'r'n", 
            Thread.CurrentThread.Name);
        // Release the Mutex.
        mut.ReleaseMutex();
    }
}

公认的答案(https://stackoverflow.com/a/10753349/1606741 撰写本文时)是正确的,但我认为使用 https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement 更清晰,并且基本相同。

一次一个线程可以执行块

private object once = new object();
public void setOutput(int value)
    {
        lock (once)
        {
            try
            {
                GPOs gpos = reader.Config.GPO;
                gpos[1].PortState = GPOs.GPO_PORT_STATE.TRUE;
                gpos[2].PortState = GPOs.GPO_PORT_STATE.TRUE;
                Thread.Sleep(WAIT);
                gpos[1].PortState = GPOs.GPO_PORT_STATE.FALSE;
                gpos[2].PortState = GPOs.GPO_PORT_STATE.FALSE;
            }
            catch (Exception ex)
            {
                logger.Error("An Exception occure while setting GPO to " + value + " " + ex.Message);
            }
        }
    }

您可以为线程命名并在方法中检查名称

这个解决方案怎么样:

private AutoResetEvent are = new AutoResetEvent();
public void setOutput(int value)
{
    // Do not wait (block) == wait 0ms
    if(are.WaitOne(0))
    {
        try
        {
            // Put your code here
        }
        finally
        {
            are.Set()
        }
    }
}

它似乎比使用锁定对象Monitor更容易(更便宜),但可能不是那么清楚。