WinForm:
I have a method called check_news in my MainApplication.
How can I create and run a Thread that will work on the method on background each time I call the method (by pushing a button, or in the start of the program)?
I know how to create a thread but how can I create new thread every time I call the function (new thread because the old one is dead)?
Should I create a new class and run the thread with the new class object and the method I need?
Where should I define the thread?
public void Example()
{
//call using a thread.
ThreadPool.QueueUserWorkItem(p => check_news("title", "news message"));
}
private void check_news(string news, string newsMessage)
{
}
You can just create a thread inside the method by writing new Thread(...).
The ... can be a method name, delegate instance, or anonymous method.
Each time this code executes, it will create a new Thread instance.
Note that it will be more efficient to use the ThreadPool instead.
I suppose the best way to achieve this is by adding it to the thread pool, it's easy and quick.
Example:
public static void Main(string[] args)
{
check_news();
}
private static void check_news()
{
ThreadPool.QueueUserWorkItem((obj) =>
{
// Fetch the news here
Thread.Sleep(1000); // Dummy
});
}
Or if you really want to deal with it yourself, this is something you could use:
public static void Main(string[] args)
{
check_news();
Console.ReadKey();
}
private static void check_news()
{
Thread t = new Thread(() =>
{
// Check news here
Thread.Sleep(1000); // Dummy
});
t.Priority = ThreadPriority.Lowest; // Priority of the thread
t.IsBackground = true; // Set it as background (allows you to stop the application while news is fetching
t.Name = "News checker"; // Make it recognizable
t.Start(); // And start it
}
But you should know that this takes a longer time to start, it doesn't reuse threads, and there's not a real advantage in it.
Or if you want more control you could use the async platform:
public static void Main(string[] args)
{
check_news(); // You can add an argument 'false' to stop it from executing async
Console.WriteLine("Done");
Console.ReadKey();
}
public delegate void Func();
public static void check_news(bool async = true)
{
Func checkNewsFunction = () =>
{
//Check news here
Thread.Sleep(1000);
};
if (async)
{
AsyncCallback callbackFunction = ar =>
{
// Executed when the news is received
};
checkNewsFunction.BeginInvoke(callbackFunction, null);
}
else
checkNewsFunction();
}
Note that the lambda expressions in all examples can just as well be replaced by regular functions. But I just use them right now, because it seems nicer as example.
Related
A ThreadPool is created that does all the work on one thread and notifies when the work is done. The thread is started and the methods Execute1 and Execute2 are not displayed, but Done1 and Done2 are not displayed, although in the debugger execution reaches handle.Finished.
public class MyThreadPool
{
private readonly Thread[] _Threads;
public delegate void ParameterizedThreadStart(object? obj);
public MyThreadPool()
{
_Threads = new Thread[1];
}
public HandleEvent QueueUserWorkItem(System.Threading.ParameterizedThreadStart callBack)
{
var thread = new Thread(callBack) { IsBackground = true };
_Threads[0] = thread;
_Threads[0].Start();
return new HandleEvent();
}
}
public class HandleEvent : EventArgs
{
public event EventHandler? Finished;
protected virtual void onFinished(object e, EventArgs s)
{
Finished?.Invoke(this, EventArgs.Empty);
}
public HandleEvent ()
{
onFinished("sddd", EventArgs.Empty);
}
}
public static class Program
{
public static void Main()
{
static void ExecuteMethod2(object execute)
{
Console.WriteLine("Hello from the thread pool.");
}
static void ExecuteMethod1(object execute)
{
Console.WriteLine("Hello from the thread pool.");
}
var thread_pool = new MyThreadPool();
var handle1 = thread_pool.QueueUserWorkItem(ExecuteMethod1);
handle1.Finished += (o, a) => { Console.WriteLine($"Done 1"); };
var handle2 = thread_pool.QueueUserWorkItem(ExecuteMethod2);
handle2.Finished += (o, a) => { Console.WriteLine($"Done 2"); };
}
}
The problem is that the onFinished method is never called. This should be called once the thread has completed execution of its callback, but it is not. For this to work the QueueUserWorkItem needs to wrap the callback in a method that does this, i.e. something like
var result = new HandleEvent();
void localExecute(object execute)
{
callBack(execute); // run the actual work
result.onFinished(); // Raise the finished method
}
var thread = new Thread(localExecute) { IsBackground = true };
_Threads[0] = thread;
_Threads[0].Start();
return result ;
However, there are other issues:
There is no actual thread pooling going on. The point of a threadpool is that threads are expensive to create, so you keep them around in a pool instead of creating new ones. The threads should be in a blocked state while in the pool, so the pool can assign the thread a task and wake it when needed.
There is no synchronization going on, so the program may very well complete before all threads are done. So you may want to return something like a ManualResetEvent that can be waited on, instead of your own custom event.
There is rarely any reason to implement your own thread pool, and doing so well is quite difficult. So I really hope you are doing this for educational purposes, and do not intend to use the result in real life.
Somewhere on my main thread i make a new thread which creates an object that is only allowed to be instantiated once through the entire application time.
Further down my main thread i have a function that makes use of this object that is also a global variable by the way.
So i wish to run this function on the same thread that the object was created.
Question is how can i achieve this when it is the Main threads decision when this function should be called?
// global variable
private static IWebDriver driver;
// Main Thread thread creation
Thread thread = new Thread(() =>
{
driver = new ChromeDriver(#"myPath");
});
thread.Start();
// some click event on main thread
myFunctionUsingDriverObject();
So i need some way to tell the function to run on the same thread as driver was created. Usually you would use the methodInvoker but the IWebDriver does not have such a method. So is there another way i can invoke the function into the thread of driver?
If anyone is wondering why i want to do this. Then it is because the UI is run on the Main Thread and then the function will freeze the UI until completion if it is also run on the main thread.
Add a reference to the WindowsBase.dll and write this code:
private static IWebDriver driver;
private static Dispatcher dispatcher = null;
AutoResetEvent waitHandle = new AutoResetEvent(false);
var thread = new Thread(() =>
{
dispatcher = Dispatcher.CurrentDispatcher;
waitHandle.Set();
Dispatcher.Run();
});
thread.Start();
waitHandle.WaitOne();
// Now you can use dispatcher.Invoke anywhere you want
dispatcher.Invoke(() =>
{
driver = new ChromeDriver(#"myPath");
});
// And async for not blocking the UI thread
dispatcher.BeginInvoke(new Action(() =>
{
myFunctionUsingDriverObject();
}));
// or using await
await dispatcher.InvokeAsync(() =>
{
});
// And when you are done, you can shut the thread down
dispatcher.InvokeShutdown();
You could use a singleton class or if you wanted to ensure that this could only run once for all applications, a service class that is based on a Mutex. I will show you the former as this seems more applicable as far as I can make out
public interface IDriverService
{
void StartDriverService();
void StopDriverService();
void PerformDriverAction();
}
Now an implementation
public class ChromeDriverService : IDriverService
{
private static ChromeDriverService instance;
private readonly Thread _thread;
private readonly ConcurrentQueue<Action> _actions = new ConcurrentQueue<Action>();
private volatile bool _running;
private ChromeDriverService()
{
_thread = new Thread();
_thread.Start();
}
public static IDriverService Instance()
{
if (instance == null)
instance = new ChromeDriverService();
return instance;
}
// This will run on the "target" _thread
public void StartDriverService()
{
while (true)
{
Action action;
if (_actions.TryDequeue(out action))
{
try
{
action();
}
catch (Exception ex) { // Handle }
}
else
{
if (!_running && _actions.IsEmpty)
return;
}
}
}
public void StopDriverService()
{
_running = false;
// IMPORTANT: Finish the logic here - we have a chance for race conditions. Dequeuing before the
// last action runs for example. This is primative, but you will have to take care of this.
while (!_actions.IsEmpty)
{
// Do stuff.
}
}
// Called from some other thread.
public void PerformDriverAction(Action action)
{
if (_running)
_actions.Enqueue(action);
}
}
This is a primitive example and I have not attempted to run or compile this (I am on my phone).
Note, I am not doing anything with the actual ChromeDriver. This class can be simply edited to work with such an object.
I hope this helps.
I am trying to accomplish the following functionality,
I get a HttpRequest and based on the request, i will create a new thread and then set some data for this thread [ local and thread specific data ] and then i will spin the thread. In the thread, i must be able to consume that data that i initialized before creating this thread anywhere before this thread ends its life.
I tried this sample and here, the greeting variable inside the thread was null. Any idea of how do i accomplish this process.
class Program
{
[ThreadStatic]
static string greeting = "Greetings from the current thread";
static void Main()
{
Console.WriteLine(greeting); // prints initial value
greeting = "Goodbye from the main thread";
Thread t = new Thread(ThreadMethod);
t.Start();
t.Join();
Console.WriteLine(greeting); // prints the main thread's copy
Console.ReadKey();
}
static void ThreadMethod()
{
// I am getting greeting as null inside this thread method.
Console.WriteLine(greeting); // prints nothing as greeting initialized on main thread
greeting = "Hello from the second thread"; // only affects the second thread's copy
Console.WriteLine(greeting);
}
}
EDIT
I am trying to accomplish something like this
class ThreadTest
{
static void Main()
{
var tcp = new ThreadContextData();
Thread t = new Thread(ThreadMethod);
tcp.SetThreadContext("hi.. from t1");
t.Start();
t.Join();
Thread t2 = new Thread(ThreadMethod);
tcp.SetThreadContext("hello.. from t2");
t2.Start();
t2.Join();
Console.ReadKey();
}
static void ThreadMethod()
{
Console.WriteLine(new ThreadContextData().GetThreadContextValue());
}
}
public class ThreadContextData
{
static ThreadLocal<string> greeting;
static ThreadContextData()
{
greeting = new ThreadLocal<string>(() => "");
}
public void SetThreadContext(string contextValue)
{
greeting.Value = contextValue;
}
public string GetThreadContextValue()
{
return greeting.Value;
}
public void ClearThreadContextValue()
{
greeting.Value = null;
}
}
The Thread class has a method Start(object) which you can use to provide parameters to the thread, provided that your thread-routine also takes a parameter:
var thr = new Thread(foo);
thr.Start(7);
private void foo(object arg)
{
int data = (int)arg; // == 7
}
However, if you have access to relatively recent .Net platform, you can use inline lambdas to get that less verbose:
var thr = new Thread(_ => foo(7, "Marie", 123.44));
thr.Start();
private void foo(int data, string name, double age)
{
// ...
}
You are setting variable in one thread and trying to read in a new thread. I think you should use something like:
Thread thread = new Thread(Start);
thread.Start("greetings from ...");
private static void Start(object o)
{
var greeting = o as string;
Console.WriteLine(greeting);
}
ThreadStatic means that each thread gets it's own version of the variable. As such, in your current code, saying greeting = "Goodbye from the main thread"; sets the main thread's version of this variable, not the thread you're running.
You can only set thread static variables from within the thread.
I would instead package all the state needed to pass to the subthread together in a class, and then pass a reference to that class as data in the thread startup function.
Also, be aware that starting threads in ASP.NET code is generally a bad idea.
I have an method Process(Progressbar) in class Blacklist
i tried to use this :
Thread thread = new Thread(() => Blacklist.Process(pgImportProcess));
it occurs an error
C# 3.0 language Feature
So how can i create a thread and parse progressbar as a parameter?
Thank in advance
have you tried:
void Invoker(){
ParameterizedThreadStart pts = Start;
Thread thread = new Thread(pts);
thread.Start(new object());
}
public void Start(object o)
{
//do stuff
}
You can't access a UI object from a different thread than it was created on. Every Control has an Invoke method that will execute a delegate on the UI thread. For example if you need to update your progress bars progress:
progressBar.Invoke(new Action() { () => progressBar.Value = updateValue; });
So you just need to use the Thread constructor that takes a ParameterizedThreadStart delegate.
Thread thread = new Thread(StartProcess);
thread.Start(pgImportProcess);
...
private static void StartProcess(object progressBar) {
Blacklist.Process((ProgressBar)progressBar);
}
Can you create a class to passing your parameter like
public class Sample
{
object _value;
public Sample(object value)
{
this._value = value;
}
public void Do()
{
// dosomething
// Invoke the Process(value)
}
}
And then
Sample p = new Sample("your parameter : Progressbar");
new Thread(new ThreadStart(p.Do)).Start();
Why does the delegate need to call the EndInvoke before the method fires? If i need to call the EndInvoke (which blocks the thread) then its not really an asynchronous call is it?
Here is the code im trying to run.
class Program
{
private delegate void GenerateXmlDelegate();
static void Main(string[] args)
{
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(null, null);
}
private static void GenerateMainXml()
{
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
The reason you need to call EndInvoke is to avoid memory leaks; .Net will store information about the function's result (or exception) until you call EndInvoke.
You can call EndInvoke in the completion handler that you give to BeginInvoke and retain the asyncronous nature.
EDIT:
For example:
class Program {
private delegate void GenerateXmlDelegate();
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(delegate {
try {
worker.EndInvoke();
} catch(...) { ... }
}, null);
}
private static void GenerateMainXml() {
Thread.Sleep(10000);
Console.WriteLine("GenerateMainXml Called by delegate");
}
}
If you want to fire an async call and forget about it, you can use the ThreadPool, like this:
ThreadPool.QueueUserWorkItem(delegate { GenerateMainXml(); });
As SLaks said, EndInvoke insures against memory leaks.
BeginInvoke is still asynchronous; consider the following code:
static void Main() {
Func<double> slowCalculator = new Func<double>(PerformSlowCalculation);
IAsyncResult slowCalculation = slowCalculator.BeginInvoke(null, null);
// lots of stuff to do while slowCalculator is doing its thing
Console.WriteLine("Result is {0}", slowCalculator.EndInvoke(slowCalculation));
}
static double PerformSlowCalculation() {
double result;
// lots and lots of code
return result;
}
If this code were written without the BeginInvoke/EndInvoke calls, PerformSlowCalculation would have to finish before Main could do the rest of its "lots of stuff"; this way, the two can be happening at the same time.
Now, in your example using a GenerateXmlDelegate, you still need EndInvoke even though you're not returning anything. The way to do this is:
static void Main(string[] args) {
GenerateXmlDelegate worker = new GenerateXmlDelegate(GenerateMainXml);
IAsyncResult result = worker.BeginInvoke(GenerateXmlComplete, null);
}
private static void GenerateXmlComplete(IAsyncResult result) {
AsyncResult realResult = result as AsyncResult;
GenerateXmlDelegate worker = result.AsyncDelegate as GenerateXmlDelegate;
worker.EndInvoke();
}