I'm trying to create a generic method that accepts a delegate. The sole purpose of the method is to ensure whatever unique code block you pass to it, is only accessed by one thread at a time. I'm pointing out the word unique as unique code blocks can run side by side, duplicate code blocks must run synchronously. Is there a clean pattern to achieve this?
You can do something like this:
namespace RunSafe
{
// Declare a delegate type
public delegate void RunSafeDelegate();
public class SafeRunner
{
private object _lock = new Object();
public void Runner( RunSafeDelegate runsafe )
{
lock( this._lock )
{
runsafe();
}
}
}
}
Ultimately Dex Star's code example lead me down the path I was looking for.
If there are any concerns please let me know. I believe this is a solid solution. Note i'm using a named mutex on purpose as there may be multiple processes involved in accessing resources.
// test code
RunSafeDelegate rsd1 = () => { /* some code i need synchronous */ };
RunSafeDelegate rsd2 = () => { /* other code i need synchronous */ };
var util = new UtilityClass();
util.RunSafe(rsd1, "myMutexName1");
util.RunSafe(rsd2, "myMutexName2");
// implementation
public class UtilityClass
{
public delegate void RunSafeDelegate();
public void RunSafe(RunSafeDelegate runSafe, string mutexName)
{
const int WAIT_ONE_TIMEOUT = 30000;
var sid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
var mar = new MutexAccessRule(sid, MutexRights.FullControl, AccessControlType.Allow);
var ms = new MutexSecurity();
ms.AddAccessRule(mar);
bool mutexCreated;
using(var mutex = new Mutex(false, mutexName, out mutexCreated, ms))
{
var signalReceived = false;
try
{
try
{
signalReceived = mutex.WaitOne(WAIT_ONE_TIMEOUT, false);
if(!signalReceived)
{
throw new TimeoutException("Exclusive access timeout for mutex: " + mutexName);
}
}
catch(AbandonedMutexException)
{
signalReceived = true;
}
runSafe();
}
finally
{
if(signalReceived)
{
mutex.ReleaseMutex();
}
}
}
}
}
Related
I have an endpoint which runs a method. I want to ensure that method will not be executed while it's running when I hit the endpoint multiple times.
I imagine I can set a variable somewhere in the thread pool or something? I'm not sure how to go about investigating this.Some leads would be appreciated.
My example:
namespace Website.Import
{
public class ImportProducts : IHttpHandler
{
private static bool running = false;
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "application/json";
if (running)
{
throw new Exception("Already running");
}
running = true;
try
{
var repo = new MemoryRepository();
var productImporter = new ProductImporter(repo);
var groupImporter = new GroupImporter(repo);
var discountImporter = new DiscountImporter(repo);
}
finally
{
running = false;
}
context.Response.Write("Done");
}
public bool IsReusable
{
get
{
return true;
}
}
}
}
You can create a lock object to ensure the action doesn't run in parallel.
private static object lockObject = new object();
lock (lockObject)
{
// your code
}
There might be a problem though: this method will get locked for every user since static variables are shared across all sessions.
This behavior might be intentional. If you want to block execution for all sessions, this code is fine. If you want to block execution for only this user, allowing the method to run once at the same time per user, you have to put the object in the session storage.
If you just want to inform the client it is already running, you could also throw an exception:
private static bool alreadyExecuting = false;
if (alreadyExecuting)
{
throw new Exception("Already running");
}
alreadyExecuting = true;
try
{
// your code
}
finally
{
alreadyExecuting = false;
}
I have following method, which is called by different instances of my ReportGenerator class. The ReportGenerator class starts a single task, which accesses following method with an Interface to the class containing this method.
public IRapportBestilling GetNextReportOrderAndLock(DateTime nextTimeoutValue, string correlationId, Func<EstimatedReportSize?, int, bool> getPermission, int taskId)
{
this.ValidateReportOrderQueueTimeout(nextTimeoutValue, correlationId);
IRapportBestillingKoe reportOrderQueue;
try
{
using (var scope = new QueryEngineSessionScope())
{
--> Lock here bool allowLargeReports = getPermission.Invoke(EstimatedReportSize.RequestForLarge, taskId);
reportOrderQueue = this.rapportBestillingKoeRepository.GetNextReportOrderQueueItem(scope, correlationId, allowLargeReports, taskId);
reportOrderQueue.Laast = true;
reportOrderQueue.Timeout = nextTimeoutValue;
this.rapportBestillingKoeRepository.Save(reportOrderQueue, scope, correlationId);
scope.Complete();
--> Release lock getPermission.Invoke(reportOrderQueue.EstimeretRapportStoerelse, taskId);
var rep = this.rapportBestillingRepository.GetDomainObjectById(reportOrderQueue.RapportBestillingId, scope, correlationId);
rep.StorRapport = (reportOrderQueue.EstimeretRapportStoerelse == EstimatedReportSize.Large);
return rep;
}
}
}
I need to only allow a single task to be executing the code block in the method shown above. I have used Interlocked as well as Monitor class to handle this problem, but this is not working since this method is called on different instances of my class. Is there an approach to handle this problem ?.
You can do it with Monitor, just lock on a static object so that it's shared between all instances.
private static object _lock = new object();
public IRapportBestilling GetNextReportOrderAndLock(...)
{
...
using (var scope = new QueryEngineSessionScope())
{
lock(_lock)
{
...
}
}
}
Hi I am new to using Parallel tasks. I have a function which I need to run multiple times in parallel. Below is the dummy code to show this,
public MyClass GlobalValue;
static void Main(string[] args)
{
Task task1 = Task.Factory.StartNew(() => SaveValue());
Task task2 = Task.Factory.StartNew(() => SaveValue());
Task task3 = Task.Factory.StartNew(() => SaveValue());
}
public void SaveValue()
{
string val = GetValueFromDB();
if (GlobalValue == NULL)
{
GlobalValue = New MyClass(val);
}
else if (GlobalValue.Key != val)
{
GlobalValue = New MyClass(val);
}
string result = GlobalValue.GetData();
}
Now the line GlobalValue = New GlobalValue(val) is called every time. Kindly help me with this. I think there is a problem with the Global Variable.
You need to synchronize the access to the shared data, as each thread will try to access it at the same time, and see that it's null, then all will allocate.
Note that the synchronization, if done via lock, will likely cause the three threads to effectively run sequentially, as only one thread can enter a lock at a time.
well, why not do
static void Main()
{
var tasks = new[]
{
Task.Factory.StartNew(() => YourFunction()),
Task.Factory.StartNew(() => YourFunction()),
Task.Factory.StartNew(() => YourFunction())
};
Task.WaitAll(tasks)
}
public static string YourFunction()
{
var yourClass = new MyClass(GetValueFromDB());
return yourClass.GetData();
}
I don't see why you need GlobalValue. Is MyClass expensive to instantiate? More notably, you don't do anything with the results so all is moot.
Since the features are available, assuming you're using .Net 4.5 (c# 5.0), you could do
static void Main()
{
await Task.WhenAll(YourFunction(), YourFunction(), YourFunction());
}
public async Task<string> YourFunction()
{
return new MyClass(GetValueFromDB()).GetData();
}
For the sake of illustration, you could still use a global variable but it would massively mitigate the benefits of parallelization. You just have to make sure you serialize access to shared state or use thread safe types that do it for you.
adapted from your example,
private readonly SemaphoreSlim globalLock = new SemaphoreSlim(1));
...
public void SaveValue()
{
string val = GetValueFromDB();
MyClass thisValue;
globalLock.Wait();
try
{
if (this.GlobalValue == NULL)
{
this.GlobalValue = new MyClass(val);
}
else if (this.GlobalValue.Key != val)
{
this.GlobalValue = new MyClass(val);
}
thisValue = this.GlobalValue
}
finally
{
globalLock.Release();
}
string result = thisValue.GetData();
}
I just trying to pass some values but it's throwing an error all the time. Can some one correct me what I am missing here?
Am getting error here
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
I want to pass this string value to ReadCentralOutQueue.
class Program
{
public void Main(string[] args)
{
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
t_PerthOut.Start();
}
public void ReadCentralOutQueue(string strQueueName)
{
System.Messaging.MessageQueue mq;
System.Messaging.Message mes;
string m;
while (true)
{
try
{
}
else
{
Console.WriteLine("Waiting for " + strQueueName + " Queue.....");
}
}
}
catch
{
m = "Exception Occured.";
Console.WriteLine(m);
}
finally
{
//Console.ReadLine();
}
}
}
}
This code:
Thread t_PerthOut = new Thread(new ThreadStart(ReadCentralOutQueue("test"));
tries to call ReadCentralOutQueue and then create a delegate from the result. That isn't going to work, because it's a void method. Normally you'd use a method group to create a delegate, or an anonymous function such as a lambda expression. In this case a lambda expression will be easiest:
Thread t_PerthOut = new Thread(() => ReadCentralOutQueue("test"));
You can't just use new Thread(ReadCentralOutQueue) as the ReadCentralOutQueue doesn't match the signature for either ThreadStart or ParameterizedThreadStart.
It's important that you understand why you're getting this error, as well as how to fix it.
EDIT: Just to prove it does work, here's a short but complete program:
using System;
using System.Threading;
class Program
{
public static void Main(string[] args)
{
Thread thread = new Thread(() => ReadCentralOutQueue("test"));
thread.Start();
thread.Join();
}
public static void ReadCentralOutQueue(string queueName)
{
Console.WriteLine("I would read queue {0} here", queueName);
}
}
You have to do it like this:
var thread = new Thread(ReadCentralOutQueue);
thread.Start("test");
Also ParameterizedThreadStart expects a delegate which takes an object as parameter so you need to change your signature to this:
public static void ReadCentralOutQueue(object state)
{
var queueName = state as string;
...
}
Parameters are not allowed as part of the ThreadStart delegate. There are several other solutions to passing a parameter to a new thread, discussed here: http://www.yoda.arachsys.com/csharp/threads/parameters.shtml
But the one that would probably be simplest in your case is the anonymous method:
ThreadStart starter = delegate { Fetch (myUrl); };
new Thread(starter).Start();
I have a problem regarding multithreading and inserting an item to an Dictionary. The following situation is what I am encoutering when insertingen subjects with duplicate id's:
private static readonly Timer bufferChecker;
private static readonly List<SubjectStartRulePair> inBuffer;
private static readonly IDictionary<Guid, Subject> beingProcessed;
private static readonly object objLock;
static InBuffer()
{
objLock = new object();
inBuffer = new List<SubjectStartRulePair>();
beingProcessed = new Dictionary<Guid, Subject>();
bufferChecker = new Timer(x => ProcessThreads(), null, 1000, 1000);
}
public static void ProcessThreads()
{
lock(objLock)
{
var bufferedItems = inBuffer.OrderBy(x => x.QueuedTime);
foreach (var item in bufferedItems)
{
if (!beingProcessed.ContainsKey(item.Subject.SubjectId)) //Important check which validates if there is already a Thread running
{
var thread = new Thread(
x =>
{
//Thread #2 is here and runs into duplicate Key
beingProcessed.Add(item.Subject.SubjectId, item.Subject);
item.StartRule(item.Subject);
beingProcessed.Remove(item.Subject.SubjectId);
});
thread.Start();
inBuffer.Remove(item);
}
}
}
}
public static void TryToExecute(Subject subject, IBusinessRule rule)
{
lock (objLock)
{
if (beingProcessed.ContainsKey(subject.SubjectId)) //Important check which validates if there is already a Thread running
{
inBuffer.Add(
new SubjectStartRulePair
{
QueuedTime = DateTime.Now,
Subject = subject,
StartRule = (x =>
{
rule.RunChildren(subject);
return true;
})
}
);
}
else
{
var thread = new Thread(
x =>
{
beingProcessed.Add(subject.SubjectId, subject);
rule.RunChildren(subject);
beingProcessed.Remove(subject.SubjectId);
});
thread.Start(); //Thread #1 is here
}
}
}
I have locked both methods, but the lock doesn't seem to work... It seems that two threads both enter the lock on the different methods. Am I missing the point of using lock()? Any idea on how I should implement this correctly? Important sidenote, the ProcessThreads() method is being called every second by a Timer (bufferChecker).
You're starting a new thread in each method - those new threads won't have (or request) the lock.
So although only one of ProcessThreads or TryToExecute can effectively run at a time, you don't have any control over the bits in the lambda expressions. If those require mutual exclusion as well, you need to put a lock statement in those lambdas.