Start a Thread from different class and parameters - c#

I would like to start the Thread with methods implemented in a external class and as well as I need to pass to this method reference to some external property.
The problem is here
Thread t = new Thread(Agent.Activate(agentParameters, ref tcpListener));
Visual Studio say that Acvivate method should return Thread. But by example below it should not.
I use this example but it does not help https://msdn.microsoft.com/en-us/library/system.threading.thread.setdata(v=vs.110).aspx. Here is my code
class TCPListenerManager
{
TcpListener tcpListener;
public TCPListenerManager(HostListenerItem hostListenerItem)
{
tcpListener = new TcpListener(IPAddress.Parse(hostListenerItem.IP4), hostListenerItem.Port);
for (int i = 0; i < hostListenerItem.ClientsMax; i++)
{
var agentParameters = new AgentParameters();
Thread t = new Thread(Agent.Activate(agentParameters, ref tcpListener));
t.Start();
}
}
} // end of class DeviceAgent
class Agent
{
[ThreadStaticAttribute]
static int threadSpecificData;
static public AgentParameters Parameters;
public static void Activate(AgentParameters agentParameters, ref TcpListener tcpListener)
{
Parameters = agentParameters;
threadSpecificData = Thread.CurrentThread.ManagedThreadId;
var socket = tcpListener.AcceptSocket();
if (socket.Connected)
{
//
// logger.Info("Socket.Connected on" + socketParameters.HostListenerItem.Name + " " + socketParameters.HostListenerItem.Url);
}
}
} // end of Agent
class AgentParameters
{
public HostListenerItem HostListenerItem { get; set; }
public AgentParameters()
{
HostListenerItem = new HostListenerItem();
}
}

You have to pass your method as a delegate to the new thread:
Thread t = new Thread(() => Agent.Activate(agentParameters, ref tcpListener));

Related

Required solution for Thread Constructor and solution to start thread for my code

I am trying to assign value to my variable in default constructor and Thread Construction. However, I am unable to identify how to solve this issue.
I have created a for loop through which I am assigning my value as well as to Start the Thread.
How can I solve ThreadStart(InitializeServer(I))?
-> Error: Method name expected
What is the other way around for this. ServerInitialization.Start();
-> If I use workerThread.Start() will all individual thread would start? Example Such as Server 1, Server 2?
ServerInitialization.cs
using System;
using System.Threading;
namespace MyApplication
{
public class ServerInitialization
{
public int serverID;
static private int ServersInStore = MainApplication.numofServers;
public ServerInitialization(int serverNum)
{
this.serverID = serverNum;
}
public static void InitializeServer(int sId)
{
ServerInitialization _id = new ServerInitialization(sId);
_id.serverID = sId;
}
public static void AssignServer(int totalServers)
{
for (int i = 0; i<totalServers; ++i)
{
Thread workerThread = new Thread(new ThreadStart(InitializeServer(i)));
ServerInitialization.Start();
}
}
}
MainApplication.cs
using System;
using System.Threading;
namespace MyApplication
{
public class MainApplication
{
public static int numofServers = 0;
static void Main(string[] args)
{
Console.WriteLine("How servers required?");
numofServers = int.Parse(Console.ReadLine());
ServerInitialization.AssignServer(numofServers);
}
}
}
Recreating my C# issue in Java project.
GenerateServer.java
import java.util.Scanner;
public class GenerateServer {
protected static int NumOfServers=4;
public static void main(String[] args) {
// TODO Auto-generated method stub
Server.InitializeServer();
}
}
Server.java
public class Server implements Runnable{
private int serverID;
//private Customer atCounter;
static private int ServersInStor=GenerateServer.NumOfServers;
public Server(int serverID)
{
this.serverID=serverID;
}
public static void InitializeServer()
{
for (int i=0; i<GenerateServer.NumOfServers; ++i)
{
Thread Server = new Thread(new Server(i));
Server.start();
}
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
Looks like you can just use an anonymous lambda function
Thread workerThread = new Thread(new ThreadStart(() => InitializeServer(i)));
Or in short:
Thread workerThread = new Thread(() => InitializeServer(i));

Adding a method call to a collection

Given a situation where I have a method SetFooInDevice(), which I call using a property as one of the arguments:
public class Program
{
public static byte Foo { get; set; }
public static void SetFooInDevice(System.IO.Ports.SerialPort sp, byte foo)
{
var txBuffer = new List<byte>();
// Format message according to communication protocol
txBuffer.Add(foo);
sp.Write(txBuffer.ToArray(), 0, txBuffer.Count);
}
public static void Main()
{
var _rnd = new Random();
var _serialPort = new System.IO.Ports.SerialPort("COM1", 9600);
_serialPort.Open();
for (int i = 0; i < 100; i++)
{
Foo = (byte)_rnd.Next(0, 255);
SetFooInDevice(_serialPort, Foo); // <-- How to add this call to a collection?
System.Threading.Thread.Sleep(100);
}
}
}
Is it possible to add the method call to a collection, in a way that the method call can be executed when running through the collection at a later time?
I want to be able to add calls to various methods to a collection, that I can run through and execute later if conditions are met (serial port open, time interval has passed, etc.).
Try this:
public static byte Foo { get; set; }
public static void SetFooInDevice(System.IO.Ports.SerialPort sp, byte foo)
{
var txBuffer = new List<byte>();
// Format message according to communication protocol
txBuffer.Add(foo);
sp.Write(txBuffer.ToArray(), 0, txBuffer.Count);
}
public static void Main()
{
List<Action> listActions = new List<Action>(); // here you create list of action you need to execute later
var _rnd = new Random();
var _serialPort = new System.IO.Ports.SerialPort("COM1", 9600);
_serialPort.Open();
for (int i = 0; i < 100; i++)
{
Foo = (byte)_rnd.Next(0, 255);
var tmpFoo = Foo; // wee need to create local variable, this is important
listActions.Add(() => SetFooInDevice(_serialPort, tmpFoo));
System.Threading.Thread.Sleep(100);
}
foreach (var item in listActions)
{
item(); // here you can execute action you added to collection
}
}
You can check this on MS docs Using Variance for Func and Action Generic Delegates
You can use Action delegate for this purpose like below
private List<Action<System.IO.Ports.SerialPort, byte>> methodCalls
= new List<Action<System.IO.Ports.SerialPort, byte>>();

How to wait for a method to finish on another thread?

I am new to multi-thread programming in C#. My problem is that I don't know how to wait for a method that is being run on another thread to finish, before it can continue to the next line. For example, something like this
public class A
{
int i;
public A()
{
i = 0;
}
protected void RunLoop()
{
while(i < 100)
{
i++;
}
}
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
runThread = new Thread(new ThreadStart(RunLoop));
running = true;
runThread.Start();
}
}
public class B
{
A classAInstance = new A();
A.Start();
Console.Writeline(i);
}
Right now, it prints 0 on the console, which is not what I want (i.e. i = 100).
What is the best way to do this? BTW, I don't have access to the runThread that is created in class A
Thanks.
EDIT:
It was a bit difficult to solve this problem without modifying a lot codes. Therefore, we ended up with adding a condition in the public void Start() with which it can decide whether to run the RunLoop in a separate thread or not. The condition was defined using an Enum field.
public void Start()
{
TimerResolution.TimeBeginPeriod(1);
running = true;
if (runningMode == RunningMode.Asynchronous)
{
runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
else
{
RunLoop();
}
}
And
public enum RunningMode { Asynchronous, Synchronous };
Thanks everyone for help.
The preferred method is to use the Task Parallel Library (TPL) and use Task with await.
If you must use Threads, then use a ManualResetEvent or ManualResetEventSlim to signal the end of a method.
void Main()
{
var a = new A();
a.Start();
a.FinishedEvent.WaitOne();
Console.WriteLine(a.Index);
}
// Define other methods and classes here
public class A
{
ManualResetEvent mre = new ManualResetEvent(false);
int i;
public EventWaitHandle FinishedEvent
{
get { return mre; }
}
public int Index
{
get { return i; }
}
public A()
{
i = 0;
}
protected void RunLoop()
{
while (i < 1000)
{
i++;
}
mre.Set();
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
}
Your life would be so much better with tasks.
Your code could be this simple:
var task = Task.Factory.StartNew(() =>
{
var i = 0;
while (i < 100)
{
i++;
}
return i;
});
Console.WriteLine(task.Result);
I like use Monitor.Wait() and Monitor.Pulse() in conjunction with "lock" operator. It works, but you must be careful, when you use this technique.
I'm added some changes to your code to demonstrate it. Code below are prints i== 100, as you want.
public class A
{
int i;
public object SyncObject
{ get; private set; }
public A()
{
SyncObject = new object();
i = 0;
}
protected void RunLoop()
{
while (i < 100)
{
i++;
}
lock (SyncObject)
{
Monitor.Pulse(SyncObject);
}
}
public void Start()
{
var runThread = new Thread(new ThreadStart(RunLoop));
runThread.Start();
}
public void PrintI()
{
Console.WriteLine("I == " + i);
}
}
public class B
{
public static void Run()
{
A classAInstance = new A();
lock (classAInstance.SyncObject)
{
classAInstance.Start();
Monitor.Wait(classAInstance.SyncObject);
}
classAInstance.PrintI();
}
}

Hot to call a method from another thread or fire a event from another thread which gets handled on the main thread

I know, the title might be confusing, but I can't really express it better in short.
Basically, I'm writing a TCP Server. I don't have a Windows Form to show, the only thing the user sees is a TrayIcon.
My TCP Server class creates a thread for listening for clients, and then additional thread for every client handling communication. When all communication is done, I want to call a method on the main thread.
I've done it by firing a event from the client communication thread which gets handled on the main thread, and all worked fine until I wanted to add desktop notifications to my application. I've build a notification using WPF (iControlNotification) and wanted to show it in the event handler I mentioned before, but I'm getting a error message saying something like "The calling thread has to be a STA Thread".
Here's some code (I removed unnecessary party):
static class Program {
[...]
[STAThread]
static void Main() {
Log("iControlServerApplication started.");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
trayIcon = new TrayIcon();
trayIcon.Display();
NotificationManager = new iControlNotificationManager();
server = new TCPServer();
server.CommandReceived += new TCPServer.CommandReceivedEventHandler(tcpServer_CommandReceived);
if (server.Start()) {
NotificationManager.ShowNotfication("iControl Server Application", "Server started. " + plugins.Count + " plugins loaded.");
Application.Run();
} else {
MessageBox.Show("Port " + server.Port + " is already in use. Server could not be started.", ApplicationName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
[...]
static void tcpServer_CommandReceived(object source, TCPServer.CommandReceivedEventArgs e) {
string toolTipText = "[" + e.Client.IPAddress + "] >> " + e.Command;
NotificationManager.ShowNotfication("iControl Server Application", toolTipText);
foreach (IiControlPlugin plugin in plugins) {
plugin.Handle(e.SplittedCommands, e.Client);
}
}
[...]
}
-
class TCPServer {
public delegate void CommandReceivedEventHandler(object source, CommandReceivedEventArgs e);
public event CommandReceivedEventHandler CommandReceived;
public class CommandReceivedEventArgs : EventArgs {
private string _command;
private string[] _splittedCommands;
private iControlClient _client;
public CommandReceivedEventArgs(string command, iControlClient client) {
_command = command;
_splittedCommands = command.Split(new Char[]{' '});
_client = client;
}
public string Command { get { return _command; } }
public string[] SplittedCommands { get { return _splittedCommands; } }
public iControlClient Client { get { return _client; } }
}
public TCPServer() {
this.tcpListener = new TcpListener(IPAddress.Any, Port);
this.icClients = new Dictionary<String, iControlClient>();
}
public Boolean Start() {
if (PortIsAvailable(Port)) {
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
Program.Log("ListeningThread started.");
return true;
} else {
return false;
}
}
private void ListenForClients() {
this.tcpListener.Start();
TcpClient client;
while (this.keepListening) {
try {
client = this.tcpListener.AcceptTcpClient();
} catch {
break;
}
iControlClient icClient = new iControlClient(client);
icClient.Thread = new Thread(new ParameterizedThreadStart(HandleClientCommunication));
icClient.Thread.Start(icClient);
}
Program.Log("Stop listening.");
}
private void HandleClientCommunication(object client) {
iControlClient icClient = (iControlClient)client;
NetworkStream clientStream = icClient.TCP.GetStream();
clientStream.ReadTimeout = 10;
int bufflen = 4096;
byte[] message = new byte[bufflen];
int bytesRead;
while (this.keepReceiving && icClient.keepConnected) {
bytesRead = 0;
try {
bytesRead = clientStream.Read(message, 0, bufflen);
} catch {
break;
}
if (bytesRead == 0) {
break;
}
ProcessReceivedData(icClient, ParseData(message, bytesRead));
}
Program.Log("[" + icClient.IPAddress + "] Connection closed.");
icClient.TCP.Close();
this.icClients.Remove(icClient.IPAddress);
}
private void ProcessReceivedData(iControlClient icClient, String[] commands) {
Program.Log("[" + icClient.IPAddress + "] >> " + String.Join(" ", commands));
if (this.CommandReceived != null) {
CommandReceived(this, new CommandReceivedEventArgs(String.Join(" ", commands), icClient));
}
NetworkStream clientStream = icClient.TCP.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("::ok");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
icClient.keepConnected = false;
}
}
-
public class iControlNotificationManager {
private iControlNotifications _notifications;
public void ShowNotfication(string caption, string message) {
if ((Boolean)Program.GetSetting("notifications", true) == false) return;
Dispatcher.CurrentDispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, new Action(
() => {
iControlNotification noti = new iControlNotification(caption, message);
noti.Show();
}));
}
}
-
public class iControlNotification : Window {
private iControlNotificationModel _notification;
public iControlNotification(string caption, string message) { // Here's the error
InitializeComponent();
_notification = new iControlNotificationModel() {
Caption = caption,
Message = message
};
this.DataContext = _notification;
}
}
So how should I call tcpServer_CommandReceived so that the Notification Window can be shown the right way?
I'm really stuck here, I really appreciate any help on this!
//How to call a method from another thread :
a) You can invoke it in other thread by passing SynchronizationContext object to it:
void Method(object s)
{
SynchronizationContext sync = s as SynchronizationContext;
sync.Post(delegate { // what to do in other thread}, null);
}
Then in code you run this method in new task, passing your sync context as object (for example):
Task t = Task.Factory.StartNew(Method, SynchronizationContext.Current);
b) You can create extension method for this purpose (here is example that i used in win forms application to update UI):
public static class ControlExtensions
{
/// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread.
public static void UIThread(this Control #this, Action code)
{
if (#this.InvokeRequired)
{
#this.BeginInvoke(code);
}
else
{
code.Invoke();
}
}
}

Passing a parameter to a thread

I have a problem using threads. There is a class like this:
public class MyThread
{
public void Thread1(int a)
{
for (int i = 0; i < 1000000; i++)
{
j++;
for (int i1 = 0; i1 < 1000; i1++)
{
j++;
}
}
MessageBox.Show("Done From Class");
}
}
and I use this below code for using it:
private void button1_Click(object sender, EventArgs e)
{
MyThread thr = new MyThread();
Thread tid1 = new Thread(new ThreadStart(thr.Thread1));
tid1.Start();
MessageBox.Show("Done");
}
I get error because of Thread1 Parameter (int a),
there isn't any problem when I haven't got any parameter.
How can I fix it?
A preferred method is the first one as you can pass multiple parameters to your method without having to cast to object all the time.
Thread t= new Thread(() => thr.Thread1(yourparameter));
t.Start();
Alternatively, you need to use parameterised thread as you are passing parameter to thread. you can also do
Thread t = new Thread (new ParameterizedThreadStart(thr.Thread1));
t.Start (yourparameter);
ofcourse your parameter has to be of object type for second example.
Threads accept a single object parameter:
public void Thread1(object a1)
{
int a = (int)a1;
...
}
Pass it like this:
Thread t = new Thread(Thread1);
t.Start(100);
You don't normally need to build delegates. Doing new ThreadStart(...) is normally useless from C# 2.0 .
Another (common) solution is to put Thread1 in another object:
public class MyThread
{
public int A;
public void Thread1()
{
// you can use this.A from here
}
}
var myt = new MyThread();
myt.A = 100;
var t = new Thread(myt.Thread1)
t.Start();
This because delegates have a reference to the containing object of the method. Clearly in this way you lose access to the caller's object... But then you could do:
public class MyThread
{
public int A;
public CallerType ParentThis;
public void Thread1()
{
// you can use this.A from here
// You can use ParentThis.Something to access the caller
}
}
var myt = new MyThread();
myt.A = 100;
myt.ParentThis = this;
var t = new Thread(myt.Thread1)
t.Start();
A final common method is to use closures, as suggested by Ehsan Ullah (the example with the () =>)

Categories

Resources