我有一个多线程应用程序。我希望只有一个线程执行我的函数,而其他线程在执行函数时传递它。我怎么能这样做?
我的方法类似于:
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);
}
}
答案 0 :(得分:11)
您可以将锁定对象与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
。
答案 1 :(得分:2)
您可以使用Mutex
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();
}
}
答案 2 :(得分:0)
您可以为线程命名并检查方法中的名称
答案 3 :(得分:0)
这个解决方案怎么样:
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
更容易(更便宜),但可能不那么清楚。
答案 4 :(得分:0)
公认的答案(撰写时为https://stackoverflow.com/a/10753349/1606741)是正确的,但我认为使用https://docs.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);
}
}
}