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();
Related
Why can't method 1 be executed correctly, through Action <'string'> updateMsgAction, to add a message to the ListBox, but method 2 can be executed correctly?
I tried using method 3 BeginInvoke(Delegate, Object[])
, the compiler displays an error.
I want that method #2 can be like method #1 become a method to call when need update message.
Method 1: UpdateMsg using Action<string>
private Action<string> updateMsgAction;
public void UpdateMsg()
{
updateMsgAction = new Action<string>( (s) =>
{
MsgList.Items.Add(s);
if (MsgList.Items.Count > 1000)
{
MsgList.Items.RemoveAt(0);
}
});
}
Method 3: using BeginInvoke(Delegate, Object[])
public delegate void MyDelegate(ListBox myControl, string myMessage);
public void DelegateMethod(ListBox myControl, string myMsg)
{
myControl.Items.Add(myMsg);
}
MQTT Server Start:
public async void StartMqttServer()
{
try
{
var mqttFactory = new MqttFactory();
if (mqttServer == null)
{
var mqttServerOptions = new MqttServerOptionsBuilder().WithDefaultEndpoint().WithDefaultEndpointPort(int.Parse(txtBoxPort.Text)).Build();
mqttServer.ClientConnectedHandler = new MqttServerClientConnectedHandlerDelegate(OnMqttServerClientConnected);
mqttServer.ClientDisconnectedHandler = new MqttServerClientDisconnectedHandlerDelegate(OnMqttServerClientDisconnected);
mqttServer.ClientSubscribedTopicHandler = new MqttServerClientSubscribedTopicHandlerDelegate(OnMqttServerCleitnSubScribedTopic);
mqttServer.ClientUnsubscribedTopicHandler = new MqttServerClientUnsubscribedTopicHandlerDelegate(OnMqttServerCleitnUnsubScribedTopic);
mqttServer.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(OnMqttServerApplicationMessageReceived);
await mqttServer.StartAsync(mqttServerOptions);
MsgList.BeginInvoke(updateMsgAction, "MQTT Server is started."); //Method 1
/*MsgList.BeginInvoke(new Action<string>((s) =>
{ MsgList.Items.Add(s); }), "MQTT Server is started."));*/ //Method 2
//MsgList.BeginInvoke(new MyDelegate(DelegateMethod), "MQTT Server is started.")); //Method 3
}
}
catch(Exception ex)
{
MsgList.BeginInvoke(updateMsgAction, "MQTT Server start fail."));
}
}
OnMqttServerApplicationMessageReceived:
public void OnMqttServerApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
{
// Method 1
MsgList.BeginInvoke(updateMsgAction,
String.Format("Client[{0}]>> Topic:{1} Payload:{2} Qos:{3} Retain:{4}",
e.ClientId, e.ApplicationMessage.Topic, e.ApplicationMessage.Payload.ToString(),
e.ApplicationMessage.QualityOfServiceLevel, e.ApplicationMessage.Retain));
}
BeginInvoke is used to execute some code in the thread in which the control was created. It's mandatory update controls in their own thread (usually in main thread) or you get an exception. So, your use or BeginInvoke is correct.
The problem is that, when you are running in the main thread and are be able to update the control, you delegate in an action the update. The action run in other thread and you are "cancelling" de BeginInvoke and getting the expected exception trying to update a control in other thread.
I use SynchronizationContext for this kind of things. In your form's code, add a variable:
private static SynchronizationContext Context;
UPDATE: And initialize in the constructor:
public YourForm()
{
this.InitializeComponent();
Context = SynchronizationContext.Current;
// Other code
}
Add this method:
private static void RunInMainThread(Action operation)
{
if (Context != SynchronizationContext.Current)
{
Context.Post(o => operation(), null);
}
else
{
operation();
}
}
If you already are running in main thread, your code run inmediatly. In other case, Post action run asynchronously in the main thread. You can use Send instead or Post to run synchronously. And use it when you need access to controls:
public void OnMqttServerApplicationMessageReceived(MqttApplicationMessageReceivedEventArgs e)
{
var msg = string.Format(
"Client[{0}]>> Topic:{1} Payload:{2} Qos:{3} Retain:{4}",
e.ClientId,
e.ApplicationMessage.Topic,
e.ApplicationMessage.Payload.ToString(),
e.ApplicationMessage.QualityOfServiceLevel,
e.ApplicationMessage.Retain);
RunInMainThread(() =>
{
MsgList.Items.Add(msg);
// Other code...
}
}
You can create an extension methods (Post and Send) for SynchronizationContext instead of RunInMainThread and reuse in your projects.
According to the content I am reading, I should be able to register a delegate of type Action to be executed upon cancelation, but the complier gives me and error stating: 'DisplayMessage' delegate can not be used in the current context. I can not tell what I am doing wrong.
Here is the code commented in the area, which I get the error...
I updated the code, and while Console.Writeline works, calling a message box method gives me an error stating can not convert from method group to Action delegate. Here is the updated code:
edit: The last functionality I was after was to call an actual method, one that perhaps has slightly different signature from Action. The following modification kind of works, except it prints the Window twice. I do not get why it is doing that since I am copying every line from the relevant Console.WriteLine lines in my code. I realized that I had a type mismatch between the method I wrote and what Register method accepts which is Action. Now I am basically trying to figure out what I get two MessageBoxs when the method signatures are the same, and the code is the same.
Thank you for everyone's feedback. The following code works the way I wanted. It is commented, and I am posting it in case someone else likes to do something similar.
using System;
using System.Threading;
using System.Windows.Forms;
namespace CancellationSource
{
internal delegate void DisplayMessage(string message);
internal static class Program
{
static void Main(string[] args)
{
CancellationTokenSource cts = new CancellationTokenSource();
ThreadPool.QueueUserWorkItem(o => Count(cts.Token, 50));
//ThreadPool.QueueUserWorkItem(o => Count(CancellationToken.None, 50));
Console.WriteLine("Press <enter> to cancel the operation.");
Console.ReadLine();
Action<Object> messageTarget;
messageTarget = Console.WriteLine;
cts.Token.Register(Console.WriteLine, null, true);
messageTarget = ShowWindowsMessage;
messageTarget ("This should print in box");
//This code opens a
//Message box only when the called thread operation is cancelled. This code calls two different methods
//of type Action<Object> when the spawned / requested thread is canceled.
//cts.Token.Register(messageTarget, null, true);
cts.Cancel();
Console.ReadLine();
}
//Notice in order to get the method below to execute upon thread cancelation, I had to make sure its
//its signature is one of Action<Object>
private static void ShowWindowsMessage(object value)
{
var message = (string)value;
MessageBox.Show(message);
}
private static void Count(CancellationToken token, Int32 countTo) {
for (int count = 0; count < countTo; count++)
{
if (token.IsCancellationRequested)
{
Console.WriteLine("Count is cancelled");
break;
}
Console.WriteLine(count);
Thread.Sleep(200);
}
Console.WriteLine("Count is done");
}
}
}
If you are not using the state object because you are passing null then you can take another overload of the Register method:
public CancellationTokenRegistration Register(
Action callback,
bool useSynchronizationContext
)
and simply call it like this:
cts.Token.Register(new Action(() => { Console.WriteLine("Hello World"); }), true);
If you want to stick to your delegate you can also use this:
cts.Token.Register(()=> messageTarget("Hello, World!"), true);
EDIT:
If Register() demands an Action<object> delegate than you could just use this type and pass only the delegate name:
Action<object> messageTarget;
messageTarget = Console.WriteLine;
messageTarget("Hello, World!");
cts.Token.Register(messageTarget, null, true);
This declares new delegate type, DisplayMessage:
internal delegate void DisplayMessage(string message);
You don't need new delegate type. You need new instance of delegate.
Just declare a method, which signature matches Action<object> signature, and use method group syntax:
internal static class Program
{
// ...
static void Main(string[] args)
{
// ...
// this line is equivalent of
// cts.Token.Register(new Action<object>(OnCancelled), null, true);
cts.Token.Register(OnCancelled, null, true);
// ...
}
// ...
static void OnCancelled(object state)
{
Console.WriteLine(state);
}
}
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();
}
}
}
}
}
Given a Task instance, how can I tell if ContinueWith has been called on it? I want to know if I'm the last task executing in a chain.
Task task = Task.FromResult();
void SomeMethod(var x) {
task = task.ContinueWith(previous => {
if (task.ContinueWith is called) return;
// do something with x...
}
}
If you meant multiple continuations. A possible solution may be like this.
class Program
{
public class TaskState
{
public bool Ended { get; set; }
}
static void Main(string[] args)
{
var task = Task.FromResult("Stackoverflow");
var state = new TaskState();
task.ContinueWith((result, continuationState) =>
{
Console.WriteLine("in first");
}, state).ContinueWith((result, continuationState) =>
{
if (!state.Ended)
Console.WriteLine("in second");
state.Ended = true;
}, state).ContinueWith((result, continuationState) =>
{
if (!state.Ended)
Console.WriteLine("in third");
state.Ended = true;
}, state);
Console.ReadLine();
}
}
You can have a static variable (a dictionary object) declared on the parent and update it with unique keyvalues when your Tasks are triggered. You can monitor this static variable to see if all the other threads has completed the execution or not.
I am using C# 2.0 and want to call a method with a couple of parameters with the help of ThreadPool.QueueUserWorkItem, so I tried as follows:
ThreadPool.QueueUserWorkItem(new WaitCallback(Multiply(2, 3)));
private int Multiply(int x,int y)
{
int z=(x*y);
return z;
}
I am getting compilation error. So please guide me, how can I call a function with multiple arguments with ThreadPool.QueueUserWorkItem?.
I have another query that when I am using ThreadPool.QueueUserWorkItem then how to use here anonymous function as a result I can write the code there instead of calling another function. If it is possible in C# v2.0 then please guide me with code.
You should declare a method which have the same definition as WaitCallback delegate. You can use the following code snippet:
ThreadPool.QueueUserWorkItem(Multiply, new object[] { 2, 3 });
public static void Multiply(object state)
{
object[] array = state as object[];
int x = Convert.ToInt32(array[0]);
int y = Convert.ToInt32(array[1]);
}
Anonymous delegate version is:
ThreadPool.QueueUserWorkItem(delegate(object state)
{
object[] array = state as object[];
int x = Convert.ToInt32(array[0]);
int y = Convert.ToInt32(array[1]);
}
, new object[] { 2, 3 });
Using a lambda expression would also work
ThreadPool.QueueUserWorkItem(state => Multiply(2,3));
Here's a fuller example which gets the result back to the initial thread, and shows how the delegate can be defined anonymously:
class Program
{
static void Main(string[] args)
{
using (MultiplyTask task = new MultiplyTask() { Multiplicands = new int[] { 2, 3 } })
{
WaitCallback cb = new WaitCallback(delegate(object x)
{
MultiplyTask theTask = x as MultiplyTask;
theTask.Result = theTask.Multiplicands[0] * theTask.Multiplicands[1];
theTask.Set();
});
ThreadPool.QueueUserWorkItem(cb, task);
Console.WriteLine("Calculating...");
if (task.WaitOne(1000))
{
Console.WriteLine("{0} times {1} equals {2}", task.Multiplicands[0], task.Multiplicands[1], task.Result);
}
else
{
Console.WriteLine("Timed out waiting for multiplication task to finish");
}
}
}
private class MultiplyTask : EventWaitHandle
{
internal MultiplyTask() : base(false, EventResetMode.ManualReset) { }
public int[] Multiplicands;
public int Result;
}
}
In my case, I needed an anonymous function. i.e., write to a stream asynchronously. So I used this:
ThreadPool.QueueUserWorkItem(state => {
serializer.Serialize(this.stream);
this.stream.Flush();
});
for passing arguments without lambda - just pack all arguments into a class/object
MyArgumentsClass m_MyArgumentsClass = new MyArgumentsClass();
//fill arguments in class
ThreadPool.QueueUserWorkItem(new WaitCallback(MyFunction), m_MyArgumentsClass);
then, in the function - cast the object into your arguments class
public void MyFunction(object msg)
{
MyArgumentsClass m_MyArgumentsClass = (MyArgumentsClass)msg;