How to access Object (PrintSystemJobInfo) from another Thread - c#

i have a STA-Thread which adds a PrintJob to a PrinterQueue. This PrintJob should be monitored and i figuered a Timer would be the right thing to do. But obviously i cannot access the PrintSystemJobInfo-Object in the timer-thread.
How can i solve this situation?
I got the idea that i have to use a synchronized object but i don't know how to and i'm not sure if this will solve my problem... Or is there another technique (dispatcher maybe?) i can make use of?
Is it possible to make the timer STA so i can create the printjob in the timer thread (sta is required for printqueue.addjob)? But i guess this would be a workaround...
Any help much appreciated...
thx, effdee
edit:
some pseudocode:
class WcfService
{
public int ServiceFunc() {
Thread staThread = new Thread(myObj.myFunc);
staThread.setSTA() and start()
staThread.join()
return myObj.status;
}
}
-
class myObj
{
public int status;
public PrintSystemJobInfo printJob;
public Dispatcher d;
public void myFunc()
{
d = CurrentDispatcher;
printJob = printQueue.AddJob(...);
if (printJob == null) status = 0;
else status = 1;
Timers.Timer timer = new Timer(invokeTimer);
timer.Start();
}
public void invokeTimer(args)
{
d.Invoke(new Action(() => { timerFunc(args) }));
}
public void timerFunc(args)
{
//access printJob problem here ;)
writePrintJobDetailsToDatabase();
}
}

You could expose the PrintSystemJobInfo Object to both threads and lock it when you use it. This should suspend the use of the object in a thread if the other one is using it.
wait, nevermind. You need to make a method, addJob, in your mainthread (with STA) which calls AddJob(). In the other thread you can invoke that method with Dispatcher.Invoke and run the method on the main thread.
Or just do this:
void Thread2()
{
Dispatcher.Invoke(new Action(() =>
{
PrintSystemJobInfo.AddJob();
//or any other methods you want executed on the main thread
}
}

Related

Avoid starting new thread with lock

Is this possible to lock method for one thread and force another to go futher rather than waiting until first thread finish? Can this problem be resolved with static thread or some proper pattern with one instance of mendtioned below service.
For presentation purposes, it can be done with static boolen like below.
public class SomeService
{
private readonly IRepository _repo;
public SomeService(IRepository repo)
{
_repo = repo;
}
private Thread threadOne;
public static bool isLocked { get; set; }
public void StartSomeMethod()
{
if(!isLocked)
{
threadOne = new Thread(SomeMethod);
isLocked = true;
}
}
public void SomeMethod()
{
while(true)
{
lots of time
}
...
isLocked = false;
}
}
I want to avoid situation when user clicked, by accident, two times to start and accidentailly second thread starts immediatelly after first finished.
You can use lock :)
object locker = new object();
void MethodToLockForAThread()
{
lock(locker)
{
//put method body here
}
}
Now the result will be that when this method is called by a thread (any thread) it puts something like flag at the beginning of lock: "STOP! You are not allowed to go any further, you must wait!" Like red light on crossroads.
When thread that called this method first, levaes the scope, then at the beginning of the scope this "red light" changes into green.
If you want to not call the method when it is already called by another thread, the only way to do this is by using bool value. For example:
object locker = new object();
bool canAccess = true;
void MethodToLockForAThread()
{
if(!canAccess)
return;
lock(locker)
{
if(!canAccess)
return;
canAccess = false;
//put method body here
canAccess = true;
}
}
Other check of canAccess in lock scope is because of what has been told on comments. No it's really thread safe. This is kind of protection that is advisible in thread safe singleton.
EDIT
After some discussion with mjwills I have to change my mind and turn more into Monitor.TryEnter. You can use it like that:
object locker = new object();
void ThreadMethod()
{
if(Monitor.TryEnter(locker, TimeSpan.FromMiliseconds(1))
{
try
{
//do the thread code
}
finally
{
Monitor.Exit(locker);
}
} else
return; //means that the lock has not been aquired
}
Now, lock could not be aquired because of some exception or because some other thread has already acuired it. In second parameter you can pass the time that a thread will wait to acquire a lock. I gave here short time because you don't want the other thread to do the job, when first is doing it.
So this solution seems the best.
When the other thread could not acquire the lock, it will go further instead of waiting (well it will wait for 1 milisecond).
Since lock is a language-specific wrapper around Monitor class, you need Monitor.TryEnter:
public class SomeService
{
private readonly object lockObject = new object();
public void StartSomeMethod()
{
if (Monitor.TryEnter(lockObject))
{
// start new thread
}
}
public void SomeMethod()
{
try
{
// ...
}
finally
{
Monitor.Exit(lockObject);
}
}
}
You can use a AutoResetEvent instead of your isLocked flag.
AutoResetEvent autoResetEvent = new AutoResetEvent(true);
public void StartSomeMethod()
{
if(autoResetEvent.WaitOne(0))
{
//start thread
}
}
public void SomeMethod()
{
try
{
//Do your work
}
finally
{
autoResetEvent.Set();
}
}

Consumer/producer locking GUI thread

I made a sample Consumer/Producer thread application, so I can learn how to properly use it.
I want it to allow for one thread to send commands to the GUI thread, to update the GUI with content.
I have it working, but there's one small issue. The GUI thread is my consumer thread, so I have it always checking for new commands (using a while loop). The issue is that because of this while loop, the GUI never displays because it's always stuck in the while loop. Note that the string Queue will eventually be replaced with a more complex object (one that holds data & command type).
I'm not sure how else to allow the GUI thread to consume commands without interrupting GUI functionality. Am I doing something wrong?
Here's my Form1.cs code (the form only contains 1 RichTextBox for showing output called OutputBox).
using System;
using System.Collections.Generic;
using System.Threading;
using System.Windows.Forms;
namespace MultiThreading
{
class ThreadCommandQueue
{
public static ThreadCommandQueue instance = new ThreadCommandQueue();
private Queue<string> m_queue;
private Object m_lock;
public static ThreadCommandQueue GetInstance()
{
return instance;
}
private ThreadCommandQueue()
{
m_queue = new Queue<string>();
m_lock = new Object();
}
public void Add(
string data_to_add)
{
lock (m_lock)
{
m_queue.Enqueue(data_to_add);
}
}
public string Get()
{
lock (m_lock)
{
if (m_queue.Count > 0)
{
return m_queue.Dequeue();
}
return null;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void PopulateThreadCommandQueue()
{
int i = 0;
while(true)
{
ThreadCommandQueue.GetInstance().Add("Item #: " + i.ToString());
i++;
}
}
private void Form1_Load(object sender, EventArgs e)
{
// Create the Command Queue....
ThreadCommandQueue.GetInstance();
// Create a Testing Producer Thread
Thread ProducerThread = new Thread(PopulateThreadCommandQueue);
ProducerThread.Start();
// The GUI thread is the Consumer, so keep checking the CommandQueue for data...
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(latest != null)
{
OutputBox.Text += latest + "\n";
}
}
}
}
}
Use ConcurrentQueue. So no locking is required to add and get from Queue.
Also you in real time you will not receive commands continuously from UI thread (while loop). If you have such scenario use a separate thread to receive outcome.
Then from the receivers thread you can update UI using Invoke command, as below.
//This method called from receiver thread
public void UpdateForm(Data d)
{
if(this.InvokeRequired)
{
this.Invoke(new MethodInvoker(() => this.UpdateFormUI(r)));
}
else
{
this.UpdateFormUI(data)
}
}
public void UpdateFormUI(Data d)
{
//Does actual ui update
}
Okay, the problem here is that you need to poll the message loop all the time to make GUI working and you also need to poll your IPC command queue all the time to make your commands working and you need this polling to happen at the same time on the same thread.
There are multiple ways to resolve this, but the easiest would be to process the message loop and when there is nothing to process, do your IPC command queue processing. For WinForms application this would be something like:
public Form1()
{
InitializeComponent();
Application.Idle += (sender, eargs) => ProcessCommands();
}
private void ProcessCommands()
{
while(true)
{
string latest = ThreadCommandQueue.GetInstance().Get();
if(string.IsNullOrEmpty(latest)) return;
OutputBox.Text += latest + "\n";
}
}

Inform another thread, that an operation is running or finished

I have multi-threaded application, where different threads may want to perform an operation. I tried to use Mutex to make sure, that thread does not start an operation if it is already running.
System.Threading.Mutex mutex;
bool isRunning = System.Threading.Mutex.TryOpenExisting(name, out mutex);
if (!isRunning)
{
RunMethod();
}
within method I created mutex, and try to release it at the end:
var mutex = new Mutex(true, name);
try{
//do stuff, it takes some time
}
finally
{
//TODO: I want to get rid of Mutex here
}
How do I get rid of mutex? Because even after I called mutex.ReleaseMutex() and mutex.Close(), it still exists and can be found. How can I inform that operation is currently running or finished?
Is there another way to do this?
Same, like CodingGorilla said, using events is easier.
I hope I understand your question well.
This example shows some events techniques:
Waiting for a thread has been started.
The use of waiting on multiple events (WaitHandle.WaitAny())
How to terminate a thread, safe.
Testing an event state without waiting (.WaitOne(0))
Here is an example:
public class MultiThreadedExample : IDisposable
{
private Thread _thread;
private ManualResetEvent _terminatingEvent = new ManualResetEvent(false);
private ManualResetEvent _runningEvent = new ManualResetEvent(false);
private ManualResetEvent _threadStartedEvent = new ManualResetEvent(false);
public MultiThreadedExample()
{
_thread = new Thread(MyThreadMethod);
_thread.Start();
_threadStartedEvent.WaitOne();
}
private void MyThreadMethod()
{
_threadStartedEvent.Set();
var events = new WaitHandle[] { _terminatingEvent, _runningEvent };
while (WaitHandle.WaitAny(events) != 0) // <- WaitAny returns index within the array of the event that was Set.
{
try
{
// do work......
}
finally
{
// reset the event. so it can be triggered again.
_runningEvent.Reset();
}
}
}
public bool TryStartWork()
{
// .Set() will return if the event was set.
return _runningEvent.Set();
}
public bool IsRunning
{
get { return _runningEvent.WaitOne(0); }
}
public void Dispose()
{
// break the whileloop
_terminatingEvent.Set();
// wait for the thread to terminate.
_thread.Join();
}
}

Communication between threads via delegates?

I am looking for a solution for interthread communication.
Thread A is the main thread of a windows app. I starts a Thread B that is working independant of thread a, they do not share code. But thread A has to get some feedback about status of thread b. I try to solve this with a delegate.
I am very sorry, I forgot to add that I have to work on .net 3.5, c#, WEC7
It is important that the code
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
is executed in context of thread a, how can I achieve this
public partial class Form1 : Form
{
//...
public void StartThread(Object obj)
{
new ClassForSecondThread(obj as Parameters);
}
private void button1_Click(object sender, EventArgs e)
{
//ParameterizedThreadStart threadstart = new ParameterizedThreadStart(startThread);
ParameterizedThreadStart threadstart = new ParameterizedThreadStart(StartThread);
Thread thread = new Thread(threadstart);
Parameters parameters = new Parameters(){MyEventHandler = OnMyEvent};
thread.Start(parameters);
}
public void OnMyEvent(string foo)
{
MessageBox.Show(foo);
}
}
//This code is executed in Thread B
public class ClassForSecondThread
{
public ClassForSecondThread(Parameters parameters)
{
if (parameters == null)
return;
MyEventhandler += parameters.MyEventHandler;
DoWork();
}
private void DoWork()
{
//DoSomething
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World");// I think this should be executed async, in Thread A
Thread.Sleep(10000);
if (MyEventhandler != null)
MyEventhandler.DynamicInvoke("Hello World again"); // I think this should be executed async, in Thread A
}
public event MyEventHandler MyEventhandler;
}
public class Parameters
{
public MyEventHandler MyEventHandler;
}
public delegate void MyEventHandler(string foo);
As you want to call the MessageBox on the main UI thread, you can achieve what you want using Control.Invoke.
Invoke((MethodInvoker)(() => MessageBox.Show(foo)));
The Invoke method can be called directly on the Form and you won't be in the context of Thread B within the delegate - the code will run on the same thread as the Form.
EDIT:
OP question: if I understood Control.Invoke correctly, it always acts in the context of a control?
Although the Invoke method uses a Control (in this case the form) to get a handle to the UI thread it is running on, the code within the delegate is not specific to the UI. If you want to add more statements and expand it to include more stuff, just do this:
string t = "hello"; //declared in the form
//Thread B context - Invoke called
Invoke((MethodInvoker)(() =>
{
//Back to the UI thread of the Form here == thread A
MessageBox.Show(foo);
t = "dd";
}));
Also, if you are updating things in a multi threaded environment where the data is accessible to more than one thread, then you will need to investigate sychronization - applying locks to data etc.
For what it is worth you can simplify your code considerably by using the new async and await keywords in C# 5.0.
public class Form1 : Form
{
private async void button1_Click(object sender, EventArgs args)
{
OnMyEvent("Hello World");
await Task.Run(
() =>
{
// This stuff runs on a worker thread.
Thread.Sleep(10000);
});
OnMyEvent("Hello World again");
}
private void OnMyEvent(string foo)
{
Message.Show(foo);
}
}
In the code above OnMyEvent is executed on the UI thread in both cases. The first call be executed before the task starts and the second call will be executed after the task completes.

How to stop a service when a thread is doing work (without using Thread.Abort)

I have a service running some different tasks in a loop until the service is stopped.
However one of these tasks i calling a web service and this call can take several minutes to complete. I want to be able to stop the service instantly, 'cancelling' the web service call without calling Thread.Abort because that causes some strange behavior even if the only thing the thread is doing is calling this web service method.
How can i cancel or break from a synchronous method call (if it's even possible)?
Or should I try a different approach?
I have tried to use the AutoResetEvent and then calling Thread.Abort which is working fine in the below code sample, but when implementing this solution in the actual service I get some unexpected behavior probably because of what's going on in the external libraries I'm using.
AutoResetEvent and Thread.Abort:
class Program
{
static void Main(string[] args)
{
MainProgram p = new MainProgram();
p.Start();
var key = Console.ReadKey();
if (key.Key == ConsoleKey.Q)
p.Stop();
}
}
class MainProgram
{
private Thread workerThread;
private Thread webServiceCallerThread;
private volatile bool doWork;
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.Start();
}
public void Stop()
{
doWork = false;
webServiceCallerThread.Abort();
}
private void DoWork()
{
try
{
while (doWork)
{
AutoResetEvent are = new AutoResetEvent(false);
WebServiceCaller caller = new WebServiceCaller(are);
webServiceCallerThread = new Thread(() => caller.TimeConsumingMethod());
webServiceCallerThread.Start();
// Wait for the WebServiceCaller.TimeConsumingMethod to finish
WaitHandle.WaitAll(new[] { are });
// If doWork has been signalled to stop
if (!doWork)
break;
// All good - continue
Console.WriteLine(caller.Result);
}
}
catch (Exception e)
{
Console.Write(e);
}
}
}
class WebServiceCaller
{
private AutoResetEvent ev;
private int result;
public int Result
{
get { return result; }
}
public WebServiceCaller(AutoResetEvent ev)
{
this.ev = ev;
}
public void TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(60000);
result = 1;
ev.Set();
}
catch (ThreadAbortException e)
{
ev.Set();
result = -1;
Console.WriteLine(e);
}
}
}
Can someone suggest a solution to this issue?
Try this
public void Start()
{
workerThread = new Thread(() => DoWork());
doWork = true;
workerThread.IsBackground = true;
workerThread.Start();
}
A thread is either a background thread or a foreground thread.
Background threads are identical to foreground threads, except that
background threads do not prevent a process from terminating. Once all
foreground threads belonging to a process have terminated, the common
language runtime ends the process. Any remaining background threads
are stopped and do not complete.
For more details see http://msdn.microsoft.com/en-us/library/system.threading.thread.isbackground.aspx
The solution is really this simple: Don't make calls that block for several minutes unless you want to block for several minutes. If there is no way to do a particular thing without blocking, potentially for several minutes, complain loudly to whoever wrote the code that imposes that painful requirement (or fix it yourself, if possible).
Once you've made the call, it's too late. You're committed. If the function you are calling doesn't provide a safe way to abort it, then there's no safe way.
As all you want to do is make one an asynchonrous web service call at a time and on each response make another call you can dispense with the worker thread and simply make an aynchronous call, register a callback and make another async call from the callback:
class Program
{
private static WebServiceCaller.TCMDelegate _wscDelegate;
private static readonly WebServiceCaller _wsCaller = new WebServiceCaller();
static void Main(string[] args)
{
_wscDelegate = _wsCaller.TimeConsumingMethod;
MakeWSCallAsync();
Console.WriteLine("Enter Q to quit");
while (Console.ReadLine().ToUpper().Trim()!="Q"){}
}
public static void MakeWSCallAsync()
{
_wscDelegate.BeginInvoke(OnWSCallComplete, null);
}
public static void OnWSCallComplete(IAsyncResult ar)
{
Console.WriteLine("Result {0}", _wscDelegate.EndInvoke(ar));
MakeWSCallAsync();
}
}
class WebServiceCaller
{
public delegate int TCMDelegate();
public int TimeConsumingMethod()
{
try
{
// Simulates a method running for 1 minute
Thread.Sleep(1000);
return 1;
}
catch (ThreadAbortException e)
{
return -1;
}
}
}
No blocking (well, the console thread is blocking on ReadLine()) and no windows kernal mode sync objects (AutoResetEvent) which are expensive.

Categories