using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Taking data from Main Thread\n->");
string message = Console.ReadLine();
ThreadStart newThread = new ThreadStart(delegate { Write(message); });
Thread myThread = new Thread(newThread);
}
public static void Write(string msg)
{
Console.WriteLine(msg);
Console.Read();
}
}
}
You can also use a the CallContext if you have some data that you want to "flow" some data with your call sequence. Here is a good blog posting about LogicalCallContext from Jeff Richter.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Taking data from Main Thread\n->");
string message = Console.ReadLine();
//Put something into the CallContext
CallContext.LogicalSetData("time", DateTime.Now);
ThreadStart newThread = new ThreadStart(delegate { Write(message); });
Thread myThread = new Thread(newThread);
}
public static void Write(string msg)
{
Console.WriteLine(msg);
//Get it back out of the CallContext
Console.WriteLine(CallContext.LogicalGetData("time"));
Console.Read();
}
}
}
There is an overload to Thread.Start that lets you pass in a parameter.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Taking data from Main Thread\n->");
string message = Console.ReadLine();
Thread myThread = new Thread(Write);
myThread.Start(message);
}
public static void Write(object obj)
{
string msg = (string)obj;
Console.WriteLine(msg);
Console.Read();
}
}
One way to get the same effect of passing a variable to a thread is to make a classwide private data member of the type you wish to pass to the thread. Set this value to whatever you want before you start the thread. If you have many threads, you will need to put a lock on this classwide data member to prevent unexpected values. Or you can use .NET native Mutex functionality to control access to the variable.
For example (didn't test this, just wrote it up on the fly):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
private string threadVariable;
static void Main(string[] args)
{
Console.WriteLine("Taking data from Main Thread\n->");
string message = Console.ReadLine();
threadVariable = "stuff";
Thread myThread = new Thread(Write);
Thread.IsBackground = true;
Thread.Start();
}
public static void Write()
{
Console.WriteLine(stuff);
Console.Read();
}
}
}
If you are asking how to pass parameters to threads, refer to this:
http://www.yoda.arachsys.com/csharp/threads/parameters.shtml
I am not sure if I understand your question correctly, but the following MSDN article shows how to pass data to a thread in the way that you are doing it (i.e., via ThreadStart and a delegate):
Passing data to thread
using System;
using System.Threading;
class Test
{
static void Main()
{
// To start a thread using a static thread procedure, use the
// class name and method name when you create the ThreadStart
// delegate. Beginning in version 2.0 of the .NET Framework,
// it is not necessary to create a delegate explicitly.
// Specify the name of the method in the Thread constructor,
// and the compiler selects the correct delegate. For example:
//
// Thread newThread = new Thread(Work.DoWork);
//
ThreadStart threadDelegate = new ThreadStart(Work.DoWork);
Thread newThread = new Thread(threadDelegate);
newThread.Start();
// To start a thread using an instance method for the thread
// procedure, use the instance variable and method name when
// you create the ThreadStart delegate. Beginning in version
// 2.0 of the .NET Framework, the explicit delegate is not
// required.
//
Work w = new Work();
w.Data = 42;
threadDelegate = new ThreadStart(w.DoMoreWork);
newThread = new Thread(threadDelegate);
newThread.Start();
}
}
class Work
{
public static void DoWork()
{
Console.WriteLine("Static thread procedure.");
}
public int Data;
public void DoMoreWork()
{
Console.WriteLine("Instance thread procedure. Data={0}", Data);
}
}
I use a separate worker class and populate a member variable in the constructor, I then use a void method as my delegate that uses the private member variable:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Taking data from Main Thread\n->");
string message = Console.ReadLine();
WorkerClass workerClass = new WorkerClass(message);
ThreadStart newThread = new ThreadStart(workerClass.DoWork);
Thread myThread = new Thread(newThread);
myThread.Start();
Console.Read();
}
}
internal class WorkerClass
{
private string _workerVariable = "";
internal WorkerClass(string workerVariable)
{
_workerVariable = workerVariable;
}
internal void DoWork()
{
Console.WriteLine(_workerVariable);
}
}
}
One handy set of classes I wrote up in vb2005 would allow the easy creation of a delegate with one to four bound arguments and zero or one unbound arguments. A huge mess of copy/paste code, since .net doesn't support variadic generics, but one could create a MethodInvoker which would call foo(bar,boz) by saying (vb.net syntax, but the approach would be the same in C#):
theMethodInvoker = InvMaker.NewInv(addressof foo, bar, boz)
theMethodInvoker() ' Calls foo(bar,boz)
which would generate an object containing fields Param1 as BarType, Param2 as BozType, and theAction as Action(of BarType, BozType). It would set those fields to bar, boz, and foo, and return a MethodInvoker which would call doIt, a method which called theAction(Param1, Param2). If I needed an Action(of Integer), I would use:
theMethodInvoker = ActionMaker(of Integer).NewInv(addressof foo, bar, boz)
theMethodInvoker(9) ' Calls foo(9,bar,boz)
Really slick. Lambdas avoid the need for a cut-and-paste library, but their internal implementation is similar. I've read that Lambdas cause difficulty with edit-and-continue; I know my method does not.
Related
I am trying to use lock with a shared object which I pass into my worker thread. In the code below, if I pass in the syncLock object in the Execute method of Worker, everything works fine.
However, if I store a local copy of the syncLock object in my Worker class, it does not work.
Obviously when I'm doing the "_syncLock = syncLock;" assignment, instead of having a reference to the shared syncLock object, I'm getting a new object. So I end up with each thread having it's own syncLock now instead of the shared object.
Is there way to store a local reference to the shared object? I thought that an object assignment is always a "reference" in C#?
Worker.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CacheConcurrency
{
class Worker
{
int _ID;
string _Request;
object _syncLock;
MyCache _TheCache;
public Worker(int ID, string Request, ref object syncLock, ref MyCache TheCache)
{
_ID = ID;
_Request = Request;
_syncLock = syncLock;
_TheCache = TheCache;
}
public void Execute()
{
lock (_syncLock)
{
if (_TheCache == null)
{
Thread.Sleep(2000);
_TheCache = new MyCache();
_TheCache.LoadCache();
Console.WriteLine("thread {0}: created and loaded the cache", _ID);
}
else
{
Console.WriteLine("thread {0}: using the existing cache", _ID);
Console.WriteLine("TheCache.MyCacheValue {0}", _TheCache.MyCacheValue);
Console.WriteLine("TheCache.CacheTimeStamp {0}", _TheCache.CacheTimeStamp);
}
}
Console.WriteLine("worker DoSomething: {0}", _Request);
}
}
}
Main.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CacheConcurrency
{
class Main
{
public MyCache TheCache = null;
public object syncLock = new object();
public void Execute()
{
List<Task> TaskList = new List<Task>();
for (int i = 0; i < 10; i++)
{
Task _Task = new Task(() => DoSomething(i, "test"));
_Task.Start();
Console.WriteLine("started Thread={0} at {1}", _Task.Id, DateTime.Now.ToString("hh:mm:ss.fff tt"));
}
Console.WriteLine("Press any key to quit the program");
while (Console.ReadKey().KeyChar == 0) ;
}
void DoSomething(int ID, string Request)
{
Worker worker = new Worker(ID, Request, ref syncLock, ref TheCache);
worker.Execute();
}
}
}
MyCache.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace CacheConcurrency
{
class MyCache
{
public int MyCacheValue;
public DateTime CacheTimeStamp;
public MyCache()
{
}
public void LoadCache()
{
MyCacheValue = 1;
CacheTimeStamp = DateTime.Now;
}
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CacheConcurrency
{
class Program
{
static void Main(string[] args)
{
Main main = new Main();
main.Execute();
}
}
}
I worked out the problem, thanks for the comments who got me on the right track. In particular, thanks to MickyD who commented on the code needing to be thread-safe which led me to the answer.
It turns out that I was protecting with lock correctly in my Execute function, however in my constructor I was still referencing the shared Cache object without a lock, which was not thread-safe and causing a race condition.
The fix is to put both the constructor call and the Execute inside the critical section/lock block like so:
void DoSomething(int ID, string Request)
{
lock(syncLock)
{
Worker worker = new Worker();
worker.Execute(ID, Request, ref TheCache);
}
}
This also simplifies the worker code, avoiding the need to store a local reference of the syncLock object and doing a lock in there.
I also agree with MickyD's other comments that this code should be re-written to use async/await, not have a cache inside the worker etc. The longevity of us using this code base is in question, so investing in the tech debt is uncertain at the moment.
I'm still trying to get the hang of this. The second part of my Main method will not execute. I believe I've called it correctly. But, obviously I didn't. A little help would be greatly appreciated!
using System;
using static System.Console;
using System.Threading;
namespace mellon_Assignment2
{
class Getting2KnowUapp
{
static void Main()
{
WriteLine("The current time is: " + DateTime.Now);
Thread.Sleep(2000);
AboutMe Me = new AboutMe();
}
}
}
using System;
using static System.Console;
using System.Threading;
namespace mellon_Assignment2
{
class AboutMe
{
public void DisplayInfo()
{
WriteLine("My Name\tAssignment 2");
Thread.Sleep(1500);
WriteLine("ITDEV110\tIntro to Object-oriented Programming");
Thread.Sleep(1500);
WriteLine("Professor\tSeptember 18th");
Thread.Sleep(1500);
}
}
}
You need to call DisplaInfo method. You are only creating the object and doing nothing with it:
AboutMe Me = new AboutMe();
Me.DisplayInfo();
Echoing the other replies, you aren't invoking the method on your class.
If you want it to occur when you create a new instance, you could move it into the constructor.
To do that, change:
public void DisplayInfo()
to
public AboutMe()
public void DisplayInfo() is it's own method and has to be called directly after initialization of the class AboutMe.
If you want the DisplayInfo() method to fire immediately upon initialization of AboutMe then simply add a constructor for AboutMe like so.
class AboutMe {
public AboutMe() {
DisplayInfo();
}
public void DisplayInfo() {
...
}
}
Then you can call:
AboutMe myvariable = new AboutMe();
I have several components in my C# code reading and setting key/value pairs in Redis in a multi-threaded context. The following minimal example
using System;
using System.Threading;
//Uncomment one of these two
//using CSRedis;
using Sider;
namespace FailureTesting
{
class UsingRedis
{
static RedisClient client = new RedisClient("localhost");
static void Main(string[] args)
{
Thread read = new Thread(Reader);
Thread set = new Thread(Setter);
read.Start();
set.Start();
}
static void Reader()
{
while(true)
{
client.Get("key");
}
}
static void Setter()
{
while (true)
{
client.Set("key", "value");
}
}
}
}
throws an Unhandled exception with Additional information: Expecting a Bulk reply, got instead69reply which makes me think that the pipe between C# and Redis is saturated. This occurs wether I use CSRedis or Sider.
On the other hand, if I use a second client, that is a second pipe for the Setter method, then everything works fine (setting static RedisClient client2 = new RedisClient("localhost"); and then client2.Set(...))
Finally, using the StackExchange.Redis library with the following equivalent code
using System;
using System.Threading;
using StackExchange.Redis;
namespace FailureTesting
{
class TestingSider
{
static IDatabase db = ConnectionMultiplexer.Connect("localhost:6379").GetDatabase();
static void Main(string[] args)
{
Thread read = new Thread(Reader);
Thread set = new Thread(Setter);
read.Start();
set.Start();
}
static void Reader()
{
while (true)
{
db.StringGet("key");
}
}
static void Setter()
{
while (true)
{
db.StringSet("key", "value");
}
}
}
}
then everything works well. The problem I have is that the StackExchange library is only supported by .NET Framework 4.5 while I have to use .Net Framework 4.0.
Could someone give me some insights about what happens here? I don't want to put locks or mutex in my code while Redis guarantees that all the operations are atomic...
I'm wondering how I can send a variable from one thread to another in a c# console application. For example,
using System;
using System.Threading;
namespace example
{
class Program
{
static void Main(string[] args)
{
int examplevariable = Convert.ToInt32(Console.ReadLine ());
Thread t = new Thread(secondthread);
t.Start();
}
static void secondthread()
{
Console.WriteLine(+examplevariable);
}
}
}
I want to make "secondthread" recognize "examplevariable".
There is an overload to Thread.Start() that takes a parameter as object. You can pass your main thread variable to that and cast it as your variable type
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int examplevariable = Convert.ToInt32(Console.ReadLine());
Thread t = new Thread(secondthread);
t.Start(examplevariable);
}
static void secondthread(object obj)
{
int examplevariable = (int) obj;
Console.WriteLine(examplevariable);
Console.Read();
}
}
}
if you want to pass multiple variable then use a model class and use property binding like below
using System;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
TestModel tm = new TestModel();
tm.examplevariable1 = Convert.ToInt32(Console.ReadLine());
tm.examplevariable2 = Console.ReadLine();
Thread t = new Thread(secondthread);
t.Start(tm);
}
static void secondthread(object obj)
{
TestModel newTm = (TestModel) obj;
Console.WriteLine(newTm.examplevariable1);
Console.WriteLine(newTm.examplevariable2);
Console.Read();
}
}
class TestModel
{
public int examplevariable1 { get; set; }
public string examplevariable2 { get; set; }
}
}
Hope this will help
An easy way to do this, but might not work in all scenarios, would be to define a static variable on the class and assign the value read in from the console to the static variable. Like so:
class Program
{
static int examplevariable;
static void Main(string[] args)
{
examplevariable = Convert.ToInt32(Console.ReadLine ());
Thread t = new Thread(secondthread);
t.Start();
}
static void secondthread()
{
Console.WriteLine(+examplevariable);
}
Also, see this question on how to pass parameters to a Thread:
ThreadStart with parameters
Is it possible to write something in the console while the program is writing something in this console ? It can be useful when you rename, or remove some files, when you do a repetitive action, and the program is writing a lot in the console. Then you will be able to write a command to stop the execution of the repetitive action while the program is continuing to write in the console. I think it's not very clear, well I illustrated you this fact with the code which I think the most apt (but I precise that it doesn't work ;) ). We have 3 classes.
The main class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
private static bool m_Write;
public static bool write
{
get { return m_Write; }
set { m_Write = value; }
}
static void Main(string[] args)
{
int index = 0;
Console.ReadLine();
m_Write = true;
Reader reader = new Reader();
while (m_Write)
{
index++;
Writer writer = new Writer(index.ToString());
}
}
}
}
The reading class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication1
{
class Reader
{
private Thread m_Reading_Thread;
private string m_text_To_Read;
public Reader()
{
m_Reading_Thread = new Thread(new ThreadStart(Read));
m_Reading_Thread.Start();
}
public void Read()
{
m_text_To_Read = Console.ReadLine();
if (m_text_To_Read == "Stop")
{
Program.write = false;
}
}
}
}
And the writing class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication1
{
class Writer
{
private Thread m_Writing_Thread;
private string m_Text_To_Write;
public Writer(string text_To_Write)
{
m_Text_To_Write = text_To_Write;
m_Writing_Thread = new Thread(new ThreadStart(Write));
m_Writing_Thread.Start();
}
public void Write()
{
Console.WriteLine(m_Text_To_Write);
}
}
}
This isn't nearly as complicated as you're trying to make it. In general there are two ways you can do this. You can start a background thread to do the writing, and have the main thread block on the console waiting for the read, or you can have the main thread writing and have the background thread do the read. I like the first solution best:
public class Program
{
private static readonly ManualResetEvent StopWriting = new ManualResetEvent(false);
private static void Main(string[] args)
{
Thread t = new Thread(WriterFunc);
t.Start();
string input;
do
{
input = Console.ReadLine();
} while (input != "stop");
// Tell the thread to stop writing
StopWriting.Set();
// And wait for the thread to exit
t.Join();
}
private static void WriterFunc()
{
int index = 0;
while (!StopWriting.WaitOne(Timeout.Infinite))
{
++index;
Console.WriteLine(index.ToString());
}
}
}
Note that I used a ManualResetEvent here rather than a Boolean flag. An even better solution would be to use a CancellationToken. Using a flag can cause all kinds of interesting problems because the compiler might determine that the variable can't change (it assumes single-threaded access). Your thread might continue running even after the variable is changed.
If you want the main thread to do the writing, and the background thread to do the reading:
public class Program
{
private static readonly ManualResetEvent StopWriting = new ManualResetEvent(false);
private static void Main(string[] args)
{
Thread t = new Thread(ReaderFunc);
t.Start();
int index = 0;
while (!StopWriting.WaitOne(Timeout.Infinite))
{
++index;
Console.WriteLine(index.ToString());
}
// Wait for the background thread to exit
t.Join();
}
private static void ReaderFunc()
{
string input;
do
{
input = Console.ReadLine();
} while (input != "stop");
// Tell the main thread to stop writing
StopWriting.Set();
}
}
Something like this would work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var w = new Writer();
var r = new Reader();
while (!r.finish)
{
w.enabled = true;
string k = Console.ReadKey(false).KeyChar.ToString();
w.enabled = false;
string line = k + Console.ReadLine();
r.Read(line);
}
}
}
class Writer
{
public bool enabled = true;
public Writer()
{
var timer = new System.Timers.Timer(1000);
timer.Elapsed += (a, b) =>
{
if(enabled)
Console.WriteLine("Test");
};
timer.Start();
}
}
class Reader
{
public bool finish = false;
public void Read(string line)
{
if (line == "stop")
{
finish = true;
}
}
}
}
Don't worry if the Writer writes above what you are typing, the Console.ReadLine() only considers what you have typed.
In the case of a console application, no two threads can write data to the screen at the exact same time.
AFAIK, in the above answer, the Writes()'s constructor is continuously executed until it finishes running. Then the control will be passed to the Reader(). So I don't think that works for what you need. Correct me if I am wrong.