This is my task class:
public class QueueTask
{
private ManualResetEvent _doneEvent;
Queue<QueueObject> _queu;
public QueueTask(ManualResetEvent doneEvent, Queue<QueueObject> queu)
{
this._doneEvent = doneEvent;
_queu = queu;
}
public void ThreadPoolCallback(Object threadContext)
{
int threadIndex = (int)threadContext;
Console.WriteLine("Thread {0} was started...", threadIndex);
QueueObject element = _queu.Dequeue();
int id = DoSomeLongOperation(element);
Console.WriteLine("Thread {0} was finished... queueObjectID: {1}", threadIndex, id);
_doneEvent.Set();
}
protected virtual int DoSomeLongOperation(QueueObject obj)
{
Random rand = new Random();
Thread.Sleep(rand.Next(5000, 10000));
return obj.ID;
}
}
And this is where I call thread pool:
public static void RunThreadPull(Queue<QueueObject> queue, int batchSize)
{
ManualResetEvent[] doneEvents = new ManualResetEvent[batchSize];
Console.WriteLine("Running batch which consist of 6 objects...");
for (int j = 0; j < batchSize; j++)
{
doneEvents[j] = new ManualResetEvent(false);
QueueTask task = new QueueTask(doneEvents[j], queue);
WaitCallback callback = new WaitCallback(task.ThreadPoolCallback);
ThreadPool.QueueUserWorkItem(callback, j);
}
WaitHandle.WaitAll(doneEvents);
Console.WriteLine("All calculations in current batch were completed!");
}
I need to set timeout to each thread in thread pull. I need to Stop thread and do another action. Don't know what action exactly, let it be method TimeoutExpiredAction(). Is exist any way to do that?
Related
Hello i am trying to pass the current index of a loop inside a thread lambda method and print it.The method will print only the last value of the index.
class Program {
public static EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset);
public static EventWaitHandle autohandle = new EventWaitHandle(false, EventResetMode.AutoReset);
static readonly int ThreadNum=3;
static void Main(string[] args) {
object lk = new object();
new Thread(() => {
while (true) {
var key = Console.ReadKey();
if(key.Key==ConsoleKey.A) {
handle.Set();
} else {
handle.Reset();
}
Thread.Sleep(3000);
}
}).Start();
for(int i=0;i<ThreadNum;i++) {
new Thread(() => {
int val = i;
Console.WriteLine($"Thread:{val} created");
while (true) {
handle.WaitOne();
Console.WriteLine($"From thread:{val}");
Thread.Sleep(1000);
}
}).Start();
}
Console.WriteLine("Hello World!");
}
}
Can someone explain to me why would i get only the last value of the index.I understand the index gets clojured (a class gets created which copies the index value) but when the first iteration enters the thread method it should clojure i=0 and keep it that way.
I think that the behaviour you are seeing is because the loop is iterating before the local variable 'val' is assigned. So by the time the statement
int val = i;
is executed for the first time, the loop has already iterated 3 times, so you get 'val' set to the last value of i.
When I run it, I get variable behaviour, due to the relative speed at which threads are created.
To get the behaviour I think you want, you need to capture the count of the loop iteration locally, like this.
class Program
{
public static EventWaitHandle handle = new EventWaitHandle(false, EventResetMode.AutoReset);
public static EventWaitHandle autohandle = new EventWaitHandle(false, EventResetMode.AutoReset);
static readonly int ThreadNum = 3;
static void Main(string[] args)
{
object lk = new object();
new Thread(() => {
while (true)
{
var key = Console.ReadKey();
if (key.Key == ConsoleKey.A)
{
handle.Set();
}
else
{
handle.Reset();
}
Thread.Sleep(3000);
}
}).Start();
for (int i = 0; i < ThreadNum; i++)
{
int temp = i;
new Thread(() => ThreadMethod(temp)).Start();
}
Console.WriteLine("Hello World!");
}
private static void ThreadMethod(object obj)
{
int val = (int)obj;
Console.WriteLine($"Thread:{val} created");
while (true)
{
handle.WaitOne();
Console.WriteLine($"From thread:{val}");
Thread.Sleep(1000);
}
}
}
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();
}
}
/*My requirements is
one threads should print even numbers and the other should print odd numbers.
These threads should print the numbers in order (1, 2, 3, 4, 5...)
I have done this code but when my commenting either method countThreadOdd.Start() or countThreadEven.Start(), it is not printing only even or odd numbers.*/
class Program
{
static Object locker = new Object();
static LinkedList<int> number = new LinkedList<int>();
static int counter = 0;
static void Main(string[] args)
{
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
//Thread Start
countThreadOdd.Start();
countThreadEven.Start();
//main thread will untill below thread is in exection mode
countThreadOdd.Join(10);
countThreadEven.Join(10);
Console.ReadLine();
}
//Odd Thread
public static void oddThread()
{
for (; counter < 10; )
{
//Lock the another thread to enter in critial area
lock (locker)
{
if (counter % 2 != 0)
{
Console.WriteLine(counter);
counter++;
}
}
}
}
//Even Thread
public static void evenThread()
{
for (; counter < 10; )
{
//Lock the another thread to enter in critial area
lock (locker)
{
if (counter % 2 == 0)
{
Console.WriteLine(counter);
counter++;
}
}
}
}
}
If you want to alternate between two threads, you can use two AutoResetEvent objects to do so, like so:
public static void oddThread()
{
for (int i = 1; i < 10; i +=2)
{
evenReady.WaitOne();
Console.WriteLine(i);
oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
Console.WriteLine(i);
evenReady.Set();
}
}
If you only want to run one of the threads, you can use a ManualResetEvent instead to effectively remove all locking.
A full example:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Dmr.Common.Resources;
namespace Demo
{
class Program
{
static EventWaitHandle evenReady;
static EventWaitHandle oddReady;
static void Main(string[] args)
{
bool countOdd = true; // Change these to true/false as wanted.
bool countEven = true;
if (countOdd && countEven)
{
evenReady = new AutoResetEvent(false);
oddReady = new AutoResetEvent(true); // Must be true for the starting thread.
}
else
{
evenReady = new ManualResetEvent(true);
oddReady = new ManualResetEvent(true);
}
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
//Thread Start
if (countOdd)
countThreadOdd.Start();
if (countEven)
countThreadEven.Start();
//main thread will untill below thread is in exection mode
if (countOdd)
countThreadOdd.Join();
if (countEven)
countThreadEven.Join();
Console.WriteLine("Done");
Console.ReadLine();
}
public static void oddThread()
{
for (int i = 1; i < 10; i +=2)
{
evenReady.WaitOne();
Console.WriteLine(i);
oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
Console.WriteLine(i);
evenReady.Set();
}
}
}
}
static AutoResetEvent evenReady = new AutoResetEvent(true);
static AutoResetEvent oddReady = new AutoResetEvent(false);
static void Main()
{
Thread countThreadOdd = new Thread(oddThread);
Thread countThreadEven = new Thread(evenThread);
countThreadOdd.Start();
countThreadEven.Start();
Console.WriteLine("Done");
Console.ReadLine();
}
public static void oddThread()
{
for (int i = 1; i < 10; i += 2)
{
oddReady.Set();
evenReady.WaitOne();
Console.WriteLine("Odd Thread: " + i);
//oddReady.Set();
}
}
public static void evenThread()
{
for (int i = 0; i < 10; i += 2)
{
oddReady.WaitOne();
evenReady.Set();
Console.WriteLine("Even Thread: " + i);
}
}
You can actually use Interlocked to communicate between threads. Interlocked allows you to share a variable concurrently across two threads.
using System;
using System.Threading;
using System.Threading.Tasks;
namespace InterlockedTest
{
class Program
{
private static long _counter = 0;
private static void printEvenTask()
{
while (Interlocked.Read(ref _counter) < 100)
{
if (Interlocked.Read(ref _counter) % 2 == 0)
{
Console.WriteLine(Interlocked.Read(ref _counter));
Interlocked.Increment(ref _counter);
}
}
}
private static void printOddTask()
{
while (Interlocked.Read(ref _counter) < 100)
{
if (Interlocked.Read(ref _counter) % 2 == 1)
{
Console.WriteLine(Interlocked.Read(ref _counter));
Interlocked.Increment(ref _counter);
}
}
}
static void Main(string[] args)
{
Task oddTask = Task.Run(() => printOddTask());
Task evenTask = Task.Run(() => printEvenTask());
oddTask.Wait();
evenTask.Wait();
Console.ReadKey();
}
}
}
Try this method. It uses Task Library.
public class OddEvenThread
{
public static async Task printEvenNumber(int n)
{
for (int i = 1; i <= n; i++)
{
if (i % 2 == 0)
Console.WriteLine(i);
}
await Task.Delay(0);
}
private static async Task printOddNumbers(int n)
{
for (int i = 1; i <= n; i++)
{
if (i % 2 == 1)
Console.WriteLine(i);
}
await Task.Delay(0);
}
public async static Task printNumbers(int n)
{
Task evenNumbers = printEvenNumber(n);
Task oddNumbers = printOddNumbers(n);
List<Task> tasks = new List<Task>() { evenNumbers, oddNumbers };
await Task.WhenAll(tasks);
}
}
Using AutoResetEvent, threads can be made wait for each other. Here, two threads write numbers from 1 to 20:
using System;
using System.Threading;
namespace oddeven
{
class Program
{
static void Main(string[] args)
{
C c = new C();
Thread t1 = new Thread(c.PrintOdd);
Thread t2 = new Thread(c.PrintEven);
t1.Start();
t2.Start();
}
}
class C
{
AutoResetEvent e1 = new AutoResetEvent(true);
AutoResetEvent e2 = new AutoResetEvent(true);
int j = 1;
public void PrintOdd()
{
while (j < 20)
{
if (j % 2 != 0)
{
Console.WriteLine(j);
j++;
}
e1.Set();
e2.WaitOne();
}
}
public void PrintEven()
{
while (j <= 20)
{
e1.WaitOne();
if (j % 2 == 0)
{
Console.WriteLine(j);
j++;
}
e2.Set();
}
}
}
}
I write an infinity loop for pulling from queue(RabbitMQ) and processing each pulled item in concurrent threads with limited count on running threads.
Now i want a solution for make a limit in thread execution count.see an example of my loop:
public class ThreadWorker<T>
{
public List<T> _lst;
private int _threadCount;
private int _maxThreadCount;
public ThreadWorker(List<T> lst, int maxThreadCount)
{
_lst = lst;
_maxThreadCount = maxThreadCount;
}
public void Start()
{
var i = 0;
while (i < _lst.Count)
{
i++;
var pull = _lst[i];
Process(pull);
}
}
public void Process(T item)
{
if (_threadCount > _maxThreadCount)
{
//wait any opration be done
// How to wait for one thread?
Interlocked.Decrement(ref _threadCount);
}
var t = new Thread(() => Opration(item));
t.Start();
Interlocked.Increment(ref _threadCount);
}
public void Opration(T item)
{
Console.WriteLine(item.ToString());
}
}
Notice that when i use a semaphore for limitation, Start() method don't wait for all running threads. my loop should after running threads with _maxThreadCount, be wait until release a thread and then push new thread for concurrent processing.
I would use Semaphore this way to control the number of threads:
public class ThreadWorker<T>
{
SemaphoreSlim _sem = null;
List<T> _lst;
public ThreadWorker(List<T> lst, int maxThreadCount)
{
_lst = lst;
_sem = new SemaphoreSlim(maxThreadCount);
}
public void Start()
{
var i = 0;
while (i < _lst.Count)
{
i++;
var pull = _lst[i];
_sem.Wait(); /*****/
Process(pull);
}
}
public void Process(T item)
{
var t = new Thread(() => Opration(item));
t.Start();
}
public void Opration(T item)
{
Console.WriteLine(item.ToString());
_sem.Release(); /*****/
}
}
I can send one parameter in the thread
class myThread
{
Thread thread;
public myThread(string name, int st)
{
thread = new Thread(this.Get_IP);
thread.Name = name;
thread.Start(st);//передача параметра в поток
thread.Join();
}
void Get_IP(object st)
{
for (int ii = 0; ii < (int)st; ii++)
{
// smth
}
}
}
But i need to send two of them
for example
for (int ii = (int)st; ii < (int)fi; ii++)
{
// smth
}
there is a way to put 2 params all together
void A(int a, int b) { }
and
ThreadStart starter = delegate { A(0, 10); };
But how can i send them to the thread?
You can pass more parameters to thread by using lambda expresion. Like this:
Thread thread = new Thread(()=>A(5,6));
Put the two variables as members in the class:
class MyThread {
private Thread _thread;
private int _start, _finish;
public MyThread(string name, int start, int finish) {
_start = start;
_finish = finish;
_thread = new Thread(Get_IP);
_thread.Name = name;
_thread.Start();
_thread.Join();
}
void Get_IP() {
for (int ii = _start; ii < _finish; ii++) {
// smth
}
}
}
Note: Calling Join right after starting the thread makes is pretty pointless to use a thread.
The Thread.Start method accepts an object as parameter. You can pass an array of your values.
thread.Start(new object[] { a, b });
Create a class that hold all of the values you need to pass and pass an instance of that class to your thread.
If you need to send 2 parametes, you can send them as any type you like, but in the method that starts new thread, you have to unbox it/them:
void MyMethod()
{
int a = 1;
int b = 2;
int[] data = new[] { a, b };
Thread t = new Thread(new ParameterizedThreadStart(StartThread));
t.Start(data);
}
private void StartThread(object obj)
{
int[] data = obj as int[];
if (data != null)
{
int a = data[0];
int b = data[1];
}
}
NOTE: method that is called by new Thread can only accppt object parameter. What is inside this object is not code`s concern, can be anything, like I boxes 2 integers.
Then you simply unbox the object to your original data types.