I see the class Thread has 4 constructors:
public Thread(ParameterizedThreadStart start);
public Thread(ThreadStart start);
public Thread(ParameterizedThreadStart start, int maxStackSize);
public Thread(ThreadStart start, int maxStackSize);
ParameterizedThreadStart and ThreadStart are delegate like this:
public delegate void ThreadStart();
public delegate void ParameterizedThreadStart(object obj);
What if I want to create thread start function that return int, for example?
I see that the constructor is good only if i want return void.
You can use the Task Parallel Library which allows you to have a return value. If you actually want a new thread to be allocated, you can use the right overload of Task.Factory.StartNew:
public int DoSomething() { return 42; }
public async Task FooAsync()
{
int value = await Task.Factory.StartNew(
() => DoSomething(), TaskCreationOptions.LongRunning);
}
If you don't actually need the new thread allocation, and can use a thread-pool thread, then using Task.Run is simpler and better:
public async Task FooAsync()
{
int value = await Task.Run(() => DoSomething());
}
Edit:
If for some odd reason you really want to use the Thread class, you can do this by closing over a variable and passing it to a delegate pass to Thread.Start and rely on the side-effect created once the thread starts running:
var x = 5;
var thread = new Thread(() =>
{
var x = DoSomething();
});
thread.Start();
thread.Join(); // This will synchronously block the thread.
Console.WriteLine(x);
Though I would definitely try to avoid this if you can use the TPL.
You can use:
public void StartThread()
{
ParameterizedThreadStart pts = new ParameterizedThreadStart(this.DoWork);
Thread th = new Thread(pts);
int i =5;
th.Start(i);
}
public void DoWork(object data)
{
Console.WriteLine("I got data='{0}'", data);
}
or shorter
Thread th = new Thread(this.DoWork);
It is possible by creating the return value from the thread. Then you should take this variable by using a lambda expression. Assign to this variable a your "return" value from the worker thread and then it is necessary to wait till thread ends from the parent thread.
int value = 5; // a variable to store the return value
var thread = new Thread(() =>
{
value = 10; // Assign value to the return variable
});
thread.Start();
thread.Join();
Console.WriteLine(value); // use your variable to show in parent thread
Related
Calling _thread.Join() causes the GetConsumingEnumerable loop to be stuck on the last element. Why does this behavior occur?
public abstract class ActorBase : IDisposable
{
private readonly BlockingCollection<Task> _queue = new BlockingCollection<Task>(new ConcurrentQueue<Task>());
private readonly Thread _thread;
private bool _isDisposed;
protected ActorBase()
{
_thread = new Thread(ProcessMessages);
_thread.Start();
}
protected void QueueTask(Task task)
{
if (_isDisposed)
{
throw new Exception("Actor was disposed, cannot queue task.");
}
_queue.Add(task);
}
private void ProcessMessages()
{
foreach (var task in _queue.GetConsumingEnumerable())
{
task.RunSynchronously();
}
}
public void Dispose()
{
_isDisposed = true;
_queue.CompleteAdding();
_thread.Join();
}
}
public class SampleActor : ActorBase
{
private string GetThreadStatus()
{
Thread.Sleep(500);
return string.Format("Running on thread {0}", Thread.CurrentThread.ManagedThreadId);
}
public async Task<string> GetThreadStatusAsync()
{
var task = new Task<string>(GetThreadStatus);
QueueTask(task);
return await task;
}
}
class Program
{
public static async Task Run()
{
using (var sa = new SampleActor())
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(await sa.GetThreadStatusAsync());
}
}
}
public static void Main(string[] args)
{
Console.WriteLine("Main thread id {0}", Thread.CurrentThread.ManagedThreadId);
var task = Task.Run(async ()=> { await Run(); });
task.Wait();
}
}
The context for this approach is that I need to make sure that all operations are executed on one OS thread, which would allow a part of the app to use different credentials than the main thread.
async-await works with continuations. To be efficient and reduce scheduling these continuations usually run on the same thread that completed the previous task.
That means in your case that your special thread is not only running the tasks, it's also running all the continuations after these tasks (the for loop itself). You can see that by printing the thread id:
using (var sa = new SampleActor())
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(await sa.GetThreadStatusAsync());
Console.WriteLine("Continue on thread :" + Thread.CurrentThread.ManagedThreadId);
}
}
When the for loop completes and the SampleActor is being disposed you call Thread.Join from the same thread your are trying to join so you get a deadlock. Your situation boils down to this:
public static void Main()
{
Thread thread = null;
thread = new Thread(() =>
{
Thread.Sleep(100);
thread.Join();
Console.WriteLine("joined");
});
thread.Start();
}
In .Net 4.6 you can solve this with TaskCreationOptions.RunContinuationsAsynchronously but in the current version you can specify the default TaskScheduler:
public Task<string> GetThreadStatusAsync()
{
var task = new Task<string>(GetThreadStatus);
QueueTask(task);
return task.ContinueWith(task1 => task1.GetAwaiter().GetResult(), TaskScheduler.Default);
}
It might be tempting to put a simple check to see if the thread you're trying to Join is Thread.CurrentThread, but that would be wrong.
Furthermore, I think the whole approach - scheduling and running cold Task objects with a custom, non-TPL-compliant scheduler - is wrong. You should be using a TPL-friendly task scheduler, similar to Stephen Toub's StaTaskScheduler. Or run a custom SynchronizationContext for your actor-serving thread (like Toub's AsyncPump) and use TaskScheduler.FromCurrentSynchronizationContext and Task.Factory.StartNew to schedue tasks with your custom scheduler (or use Task.Start(TaskScheduler) if you have to deal with cold tasks).
This way, you'll have full control of where tasks and their continuations run, as well as of task inlining.
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();
Sending Parameters to the Function called by a thread in C#,
this is my code:
myThread = new Thread(new ThreadStart(myfunc));
myThread.Start(i);
public void myfunc(int i)
{
...
}
I get error:
No overload for 'installDrivers' matches delegate
'system.Threading.ThredStart'
You can use a ParameterizedThreadStart.
Thread myThread = new Thread(new ParameterizedThreadStart(myfunc));
myThread.Start(i);
And your function
public void myfunc(object i)
{
int myInt = Convert.ToInt32(i);
}
Another option, utilizing lambdas makes it easy to call functions with any number of parameters, it also avoids the rather nasty conversion from object in the one parameter case:
int paramA = 1;
string paramB = "foo";
var myThread = new Thread(() => SomeFunc(paramA, paramB));
myThread.Start();
public void SomeFunc(int paramA, string paramB)
{
// Do something...
}
use this:
myThread = new Thread(new ParameterizedThreadStart(myfunc));
myThread.Start(i);
public void myfunc(object i) {... }
it might be usefull for your issue
Unless you are using C# < 2.0, you don't need to create a delegate. You can let the compiler implicitly create it for you.
myThread = new Thread(myfunc);
myThread.Start(i);
public void myfunc(object i)
{
int i2 = (int)i; // if i is an int
}
but note that the Thread constructor accepts only two types of delegates: one that is parameterless (ThreadStart) and one that accepts an object parameter (ParameterizedThreadStart). So here we are using the second one.
I've placed some very basic code below of what I'm trying to do. I have the 'DoSomethingAshnc' method that performs an Asynchronous operation. I would like the 'DoSomething' method to be a Synchronous method that doesn't take in the action parameter and returns an int.
public void DoSomething(Action<int> actionToPerformOnComplete)
{
DoSomethingAsync(delegate(int val)
{
actionToPerformOnComplete(val);
});
}
Is it even possible to have 'DoSomething' return an integer as if the method was happening synchronously?
You'd need to add something in the end of your sync method, to tell it to wait for the other call to finish. I'm assuming your async method will have an event on to tell the caller when it's finished.
If so then I'd suggest using something like a ManualResetEvent, waiting on it in your sync thread, and set it in the Finish event receiver for the async one.
Example:
public void DoSomething(Action<int> actionToPerformOnComplete)
{
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(delegate(int val)
{
try
{
actionToPerformOnComplete(val);
}
finally
{
mre.Set();
}
});
mre.WaitOne();
}
As others have mentioned, you need to wait for your async method to finish. To do that without passing that Action parameter to your method, use this code:
public int DoSomething()
{
int result;
ManualResetEvent mre = new ManualResetEvent(false);
DoSomethingAsync(val => {result = val; mre.Set(); });
mre.WaitOne();
return result;
}
This executes the async method, waits for it to finish and assigns the result to a local variable. This result is returned.
Yes. All you have to do is to put this line of code:
IAsyncResult asycn = ... // make a call to Async and get back IAsyncResult
while(!asycn.IsCompleted)
{
Thread.Sleep( ....);
}
UPDATE
Just as some asked, a correctly designed async operation will implement async pattern MSDN:
An asynchronous operation that uses
the IAsyncResult design pattern is
implemented as two methods named
BeginOperationName and
EndOperationName that begin and end
the asynchronous operation
OperationName respectively. For
example, the FileStream class provides
the BeginRead and EndRead methods to
asynchronously read bytes from a file.
These methods implement the
asynchronous version of the Read
method.
using System;
using System.Threading;
namespace qqq
{
class Program
{
public static void DoAsync(Action<int> whenDone)
{
new Thread(o => { Thread.Sleep(3000); whenDone(42); }).Start();
}
static public int Do()
{
var mre = new ManualResetEvent(false);
int retval = 0;
DoAsync(i => { retval = i; mre.Set(); });
if (mre.WaitOne())
return retval;
throw new ApplicationException("Unexpected error");
}
static void Main(string[] args)
{
Console.WriteLine(Do());
}
}
}