Is it a good idea to use longtime Thread.Sleep? - c#

I have a job list. Each job has its own run time. They need to run when it comes time. I think two different ways.
public class Job
{
public int JobPeriod {get;set;} // for example as hour: daily = 24, weekly = 7 * 24, monthly = 30 * 24
public DateTime RunTime {get;set}
}
First Way :
I start a new main thread. This thread checks jobs at certain time interval (5 sec, 10 sec etc.). When a job's run time has come, the main thread will start and finish the job. The main thread which continually run in this way.
while (true)
{
lock (Locker)
{
// checks job list.
var jobs = foo.GetIncomingTimeJobs();
foreach (var job in jobs)
{
ParameterizedThreadStart ts = RunJob;
var th = new Thread(ts);
th.Start(job);
}
Thread.Sleep(10000);
}
}
public void RunJob(Job job)
{
// do somethings
}
Second Way :
When application is started, I create a new thread for each job in the job list. All of these created threads will start. When Job's thread is started, job's thread checks the job's run time.
For example :
var jobs = foo.GetAllJobs();
foreach (var job in jobs)
{
ParameterizedThreadStart ts = RunJob;
var th = new Thread(ts);
th.Start(job);
}
public void RunJob(Job job)
{
while (true)
{
lock (Locker)
{
// do somethings
var period = job.JobPeriod * 60 * 1000;
Thread.Sleep(period);
}
}
}
If there are ten jobs , there will be ten threads. And These ten threads will never end. will sleep, will continue, will sleep, will continue ...
Is it normal for threads to sleep such a long time ? Which way should I use ? Or Is there another way of doing such a thing?

Both approaches are in most cases incorrect. Usual solution for this kind of problems is using System.Threading.Timer. Sample code for your case can look like that:
private void CheckJobs(object state)
{
lock (Locker)
{
// checks job list.
var jobs = foo.GetIncomingTimeJobs();
foreach (var job in jobs)
{
var thread = new Thread(foo);
thread.Start();
}
}
}
private void StartProcessing()
{
var timer = new System.Threading.Timer(CheckJobs, null, 0, 10000);
}
When you call StartProcessing() function, the timer will be initialized and jobs list will be checked every 10 seconds.
If you go with Thread.Sleep() your application will become very unresponsive.

Related

Why do I seem to have so few threads

I am trying to understand some code (for performance reasons) that is processing tasks from a queue. The code is C# .NET Framework 4.8 (And I didn't write this stuff)
I have this code creating a timer that from what I can tell should use a new thread every 10 seconds
_myTimer = new Timer(new TimerCallback(OnTimerGo), null, 0, 10000 );
Inside the onTimerGo it calls DoTask() inside of DoTask() it grabs a task off a queue and then does this
System.Threading.Tasks.Task.Factory.StartNew(ProcessTask, task).ContinueWith(c => DoTask());
My reading of this is that a new thread should start running OnTimerGo every 10 seconds, and that thread should in parralel run ProcessTask on tasks as fast as it can get them from the queue.
I inserted some code to call ThreadPool.GetMaxThreads and ThreadPool.GetAvailableThreads to figure out how many threads were in use. Then I queued up 10,000 things for it to do and let it loose.
I never see more then 4 threads in use at a time. This is running on a c4.4xlarge ec2 instance... so 16 vCPU 30 gb mem. The get max and available return over 2k. So I would expect more threads. By looking at the logging I can see that a total of 50ish different threads (by thread id) end up doing the work over the course of 20 minutes. Since the timer is set to every 10 seconds, I would expect 100 threads to be doing the work (or for it to finish sooner).
Looking at the code, the only time a running thread should stop is if it asks for a task from the queue and doesn't get one. Some other logging shows that there are never more than 2 tasks running in a thread. This is probably because they work is pretty fast. So the threads shouldn't be exiting, and I can even see from the logs that many of them end up doing as many as 500 tasks over the 20 minutes.
so... what am I missing here. Are the ThreadPool.GetMaxThreads and ThreadPool.GetAvailableThreads not accurate if run from inside a thread? Is something shutting down some of the threads while letting others keep going?
EDIT: adding more code
public static void StartScheduler()
{
lock (TimerLock)
{
if (_timerShutdown == false)
{
_myTimer = new Timer(new TimerCallback(OnTimerGo), null, 0, 10 );
const int numberOfSecondsPerMinute = 60;
const int margin = 1;
var pollEventsPerMinute = (numberOfSecondsPerMinute/SystemPreferences.TaskPollingIntervalSeconds);
_numberOfTimerCallsForHeartbeat = pollEventsPerMinute - margin;
}
}
}
private static void OnTimerGo(object state)
{
try
{
_lastTimer = DateTime.UtcNow;
var currentTickCount = Interlocked.Increment(ref _timerCallCount);
if (currentTickCount == _numberOfTimerCallsForHeartbeat)
{
Interlocked.Exchange(ref _timerCallCount, 0);
MonitoringTools.SendHeartbeatMetric(Heartbeat);
}
CheckForTasks();
}
catch (Exception e)
{
Log.Warn("Scheduler: OnTimerGo exception", e);
}
}
public static void CheckForTasks()
{
try
{
if (DoTask())
_lastStart = DateTime.UtcNow;
_lastStartOrCheck = DateTime.UtcNow;
}
catch (Exception e)
{
Log.Error("Unexpected exception checking for tasks", e);
}
}
private static bool DoTask()
{
Func<DataContext, bool> a = db =>
{
var mtid = Thread.CurrentThread.ManagedThreadId;
int totalThreads = Process.GetCurrentProcess().Threads.Count;
int maxWorkerThreads;
int maxPortThreads;
ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxPortThreads);
int AvailableWorkerThreads;
int AvailablePortThreads;
ThreadPool.GetAvailableThreads(out AvailableWorkerThreads, out AvailablePortThreads);
int usedWorkerThreads = maxWorkerThreads - AvailableWorkerThreads;
string usedThreadMessage = $"Thread {mtid}: Threads in Use count: {usedWorkerThreads}";
Log.Info(usedThreadMessage);
var taskTypeAndTasks = GetTaskListTypeAndTasks();
var task = GetNextTask(db, taskTypeAndTasks.Key, taskTypeAndTasks.Value);
if (_timerShutdown)
{
Log.Debug("Task processing stopped.");
return false;
}
if (task == null)
{
Log.DebugFormat("DoTask: Idle in thread {0} ({1} tasks running)", mtid, _processingTaskLock);
return false;
}
Log.DebugFormat("DoTask: starting task {2}:{0} on thread {1}", task.Id, mtid, task.Class);
System.Threading.Tasks.Task.Factory.StartNew(ProcessTask, task).ContinueWith(c => DoTask());
Log.DebugFormat("DoTask: done ({0})", mtid);
return true;
};
return DbExtensions.WithDbWrite(ctx => a(ctx));
}
The Task.Factory.StartNew by default doesn't create a new thread. It borrows a thread from the ThreadPool instead.
The ThreadPool is intended as a small pool of reusable threads, to help amortize the cost of running frequent and lightweight operations like callbacks, continuations, event handers etc. Depleting the ThreadPool from available workers by scheduling too much work on it, results in a situation that is called saturation or starvation. And as you've already figured out, it's not a happy situation to be.
You can prevent the saturation of the ThreadPool by running your long-running work on dedicated threads instead of ThreadPool threads. This can be done by passing the TaskCreationOptions.LongRunning as argument to the Task.Factory.StartNew:
_ = Task.Factory.StartNew(ProcessTask, task, CancellationToken.None,
TaskCreationOptions.LongRunning,
TaskScheduler.Default).ContinueWith(t => DoTask(), CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default);
The above code schedules the ProcessTask(task) on a new thread, and after the invocation is completed either successfully or unsuccessfully, the DoTask will be invoked on the same thread. Finally the thread will be terminated. The discard _ signifies that the continuation Task (the task returned by the ContinueWith) is fire-and-forget. Which, to put it mildly, is architecturally suspicious. 😃
In case you are wondering why I pass the TaskScheduler.Default explicitly as argument to StartNew and ContinueWith, check out this link.
My reading of this is that a new thread should start running OnTimerGo every 10 seconds, and that thread should in parralel run ProcessTask on tasks as fast as it can get them from the queue.
Well, that is definitely not what's happening. It's a lot of uncertainty about your code, but it's clear that another DoTask is starting AFTER ProcessTask completes. And that is not parallel execution. Your line of code is this
System.Threading.Tasks.Task.Factory.StartNew(ProcessTask, task).ContinueWith(c => DoTask());
I suggest you to start another DoTask right there like this:
System.Threading.Tasks.Task.Factory.StartNew(ProcessTask, task);
DoTask();
Make sure your code is ready for parallel execution, though.

Multithreading and change Priority

I create 3 Threads in main with 3 different method.
Thread t1 = new Thread(FirstThread);
Thread t2 = new Thread(SecondThread);
Thread t3 = new Thread(ThirdThread);
I need measured time on every thread and search less of them.
The time is measured with Stopwatch. I didn't find another way(in c/c++ i know method GetThreadTimes).
static void FirstThread()
{
Stopwatch stopwatch = Stopwatch.StartNew();
try
{
Enumerable.Range(1, 10000).Select(x => x).Sum();
}
finally
{
stopwatch.Stop();
Console.WriteLine(stopwatch.Elapsed);
}
}
After (on task) Dynamic change Thread's priority and again start method example:
thr2.priority = ThreadPriority.Highest;
I don't understand as i could begun threads with changed priority if this is IMPOSSIBLE, because thread start 1 time.
Out on display time with normal and low priority all threads.
p.s. I think that Stopwatch compared variable cast to double or I don't see any other way...
double timeInSecondsPerN = Stopwatch1.Elapsed.TotalMilliseconds
The main question to look the work of threads with different priorities in the program runtime
Thread priority will not necessarily make a task faster or accomplish 'more work'
If you set 3 threads to all be priority highest - then they will all be competing for CPU cycles at the same speed/rate, probably the same speed as if they were all thread priority BelowNormal.
All it means is that if your application gets to the point of being deadlocked and competing for CPU Cycles, it knows which thread to satisfy first.
This feature of .Net loses its benefits if you set all threads to the same high value. The feature only has value, if you use the Higher priority settings for threads that genuinely need to be satisfied before all others within your application.
Eg: Important computational tasks with low IO usage. (Encryption, Cryptocurrency, Hashing etc)
If your application is not getting to the point of being thread-locked or utilizing 100% of a cpu core, then the priority feature will never kick in.
The Microsoft website on Thread.Priority demonstrates the effect of priority well.
https://msdn.microsoft.com/en-us/library/system.threading.thread.priority(v=vs.110).aspx
using System;
using System.Threading;
using Timers = System.Timers;
class Test
{
static void Main()
{
PriorityTest priorityTest = new PriorityTest();
Thread thread1 = new Thread(priorityTest.ThreadMethod);
thread1.Name = "ThreadOne";
Thread thread2 = new Thread(priorityTest.ThreadMethod);
thread2.Name = "ThreadTwo";
thread2.Priority = ThreadPriority.BelowNormal;
Thread thread3 = new Thread(priorityTest.ThreadMethod);
thread3.Name = "ThreadThree";
thread3.Priority = ThreadPriority.AboveNormal;
thread1.Start();
thread2.Start();
thread3.Start();
// Allow counting for 10 seconds.
Thread.Sleep(10000);
priorityTest.LoopSwitch = false;
}
}
class PriorityTest
{
static bool loopSwitch;
[ThreadStatic] static long threadCount = 0;
public PriorityTest()
{
loopSwitch = true;
}
public bool LoopSwitch
{
set{ loopSwitch = value; }
}
public void ThreadMethod()
{
while(loopSwitch)
{
threadCount++;
}
Console.WriteLine("{0,-11} with {1,11} priority " +
"has a count = {2,13}", Thread.CurrentThread.Name,
Thread.CurrentThread.Priority.ToString(),
threadCount.ToString("N0"));
}
}
// The example displays output like the following:
// ThreadOne with Normal priority has a count = 755,897,581
// ThreadThree with AboveNormal priority has a count = 778,099,094
// ThreadTwo with BelowNormal priority has a count = 7,840,984

Thread not run immediately when using more than 4 BackgroundWorker

I use multiple BackgroundWorker control to run some task as multithreading. But I found that when using more than 4 BackgroundWoker, the one from 4th forward delay more than second to actually execute from when calling RunWorkerAsync.
Could help me how can I start all backgroundworker immediately?
class TaskLog
{
public int task_id;
public DateTime call_time;
public DateTime start_time;
public DateTime end_time;
}
BackgroundWorker[] bws = new BackgroundWorker[18];
int[] tasks = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
Queue<TaskLog> queueTask;
TaskLog[] records;
int task_complete = 999;
private void button1_Click(object sender, EventArgs e)
{
if (task_complete < tasks.Length) return;
task_complete = 0;
records = tasks.Select(t => new TaskLog { task_id = t }).ToArray();
queueTask = new Queue<TaskLog>(records);
for (int i = 0; i < bws.Length && queueTask.Count > 0; ++i)
{
bws[i] = new BackgroundWorker();
bws[i].DoWork += new DoWorkEventHandler(download_vid_work);
bws[i].RunWorkerCompleted += new RunWorkerCompletedEventHandler(download_vid_complete);
var x = queueTask.Dequeue();
x.call_time = DateTime.Now;
bws[i].RunWorkerAsync(x);
//Debug.WriteLine("start " + x.task_id);
}
}
void download_vid_work(object sender, DoWorkEventArgs e)
{
var record = (TaskLog)e.Argument;
record.start_time = DateTime.Now;
//Debug.WriteLine("actually start " + record.task_id);
Thread.Sleep(10000); // 10s
e.Result = record;
}
void download_vid_complete(object sender, RunWorkerCompletedEventArgs e)
{
var record = (TaskLog)e.Result;
record.end_time = DateTime.Now;
//Debug.WriteLine("complete " + item.ToString());
++task_complete;
if (task_complete == tasks.Length)
{
Debug.WriteLine("all tasks are completed!");
foreach (var r in records)
{
Debug.WriteLine("task {0} delay time: {1}", r.task_id, (r.start_time - r.call_time).TotalMilliseconds.ToString("0,0"));
}
}
else if (queueTask.Count > 0)
{
var bw = (BackgroundWorker)sender;
var nextTask = queueTask.Dequeue();
bw.RunWorkerAsync(nextTask);
nextTask.call_time = DateTime.Now;
}
}
Here is log result after run:
all tasks are completed!
task 1 delay time: 22
task 2 delay time: 24
task 3 delay time: 24
task 4 delay time: 23
task 5 delay time: 1,005
task 6 delay time: 2,002
task 7 delay time: 3,003
task 8 delay time: 4,003
task 9 delay time: 5,004
task 10 delay time: 6,005
The ThreadPool class, which manages the thread pool threads used for BackgroundWorker (and other needs), does not maintain an infinite number of worker threads ready to run.
You can configure the actual number of idle threads (*), using the ThreadPool.SetMinThreads() method. As you can see in your case, when you initially start your program, there are four idle threads ready to accept work right away. The default number of idles threads depends on a variety of things related to the OS version and configuration.
Once there are more queued work items for the thread pool than there are threads to service them, the ThreadPool class does not create new threads right away. It waits for a short period of time (as you can see from your test, one second), on the assumption that it's possible one of the other tasks may finish soon and it will be able to reuse that thread rather than going to all the trouble of creating yet another thread (which incurs its own overhead and would even slow down the work of the threads already running).
In general, you should avoid overriding the default values for the thread pool, as they are generally set correctly given your OS version, hardware, etc. For example, it won't help to have more CPU-bound threads running than you have CPU cores on the machine. Letting the ThreadPool class decide when and how to run your worker threads is usually the best approach.
(*) The above is a bit of an over-simplification. In newer versions of .NET, the minimum number of threads may or may not actually exist at any given time. If work items are queued when there are fewer than the minimum number, ThreadPool will immediately create new threads as needed up to the minimum. Beyond that, it then shifts to its more elaborate creation and scheduling logic.

Monitor.Pulse(this) does not trigger Monitor.Wait(this);

I'm trying to get Monitor.Pulse(this) to trigger Monitor.Wait(this) in my code. I think my Wait statements are all running at some point with no Pulse. I have 5 different threads run by 5 different objects, each representing a queue with different priority. I'm trying to get each thread to run with a certain priority without using the thread priority attribute (i.e. normal, abovenormal, etc.). Anyways, point is that each thread only runs once and then it seems they are stuck at the Monitor.Wait(this) part in the thread that runs for each queue. Does anyone know why the Monitor.Pulse(this) doesn't trigger the Monitor.Wait(this) and continue the cycle. Each thread should be triggered one after the other by the Monitor.Wait(this) and the while loop that uses the Global variable GlobalCount. I think the problem must occur in my Beta method in the first class (Msg class) at the top where this triggering occurs. Or in my main method, although I'm less sure of that part having an issue.
What happens is it will execute a few lines and then start a new line but won't print anything else. The code is still running. I also tried removing the Monitor.Pulse and Monitor.Wait and it partially works, but every time the delta object's beta method runs its thread it is replaced by the alpha method. Does anyone know why this is and how I can get Pulse and Wait to work?
Here is my code (ignore some of the comments):
// StopJoin.cs
using System;
using System.Threading;
using System.Collections;
public class Msg
{
string message;
int priority;
public Msg(string ms, int pr)
{message = ms;
priority = pr;}
// This method that will be called when the thread is started
public void Beta()
{
while(true){
//Console.WriteLine("asdfasdfs");
Console.WriteLine(message+":"+GlobalClass.globalCount);
lock(this) // Enter synchronization block
{
while((priority - 1) != GlobalClass.globalCount){
//Console.WriteLine(GlobalClass.globalCount);
try
{
// Waits for the Monitor.Pulse in WriteToCell
//Console.WriteLine("beginning");
//Monitor.Wait(this);
//Console.WriteLine("end");
}
catch (SynchronizationLockException e)
{
Console.WriteLine(e);
}
catch (ThreadInterruptedException e)
{
Console.WriteLine(e);
}
if(GlobalClass.globalCount >= 5)
GlobalClass.globalCount = 0;
}
Console.WriteLine(message+".Beta is running in its own thread.");
for(int i = 0;i<priority;i++)
{
Console.WriteLine("sending message...");
}
if(GlobalClass.globalCount < 5)
GlobalClass.globalCount = GlobalClass.globalCount + 1;
//Monitor.Pulse(this); // Pulse tells Cell.WriteToCell that
//Console.WriteLine(GlobalClass.globalCount);
}
}
}
}
public class Alpha
{
Msg the_message = new Msg("Alpha",1);
public void doWork()
{the_message.Beta();}
};
public class Charlie
{
Msg the_message = new Msg("Charlie",2);
public void doWork()
{the_message.Beta();}
};
public class Delta
{
Msg the_message= new Msg("Alpha",3);
public void doWork()
{the_message.Beta();}
};
public class Echo
{
Msg the_message= new Msg("Echo",4);
public void doWork()
{the_message.Beta();}
};
public class Foxtrot
{
Msg the_message= new Msg("Foxtrot",5);
public void doWork()
{the_message.Beta();}
};
static class GlobalClass
{
private static int global_count = 0;
public static int globalCount
{
get{return global_count;}
set{global_count = value;}
}
}
public class Simple
{
public static int Main()
{
GlobalClass.globalCount = 2;
long s = 0;
long number = 100000000000000000;
Console.WriteLine("Thread Start/Stop/Join Sample");
Alpha oAlpha = new Alpha();
Charlie oCh = new Charlie();
Delta oDe = new Delta();
Echo oEc = new Echo();
Foxtrot oFo = new Foxtrot();
// Create the thread object, passing in the Alpha.Beta method
// via a ThreadStart delegate. This does not start the thread.
Thread oThread = new Thread(new ThreadStart(oAlpha.doWork));
Thread aThread = new Thread(new ThreadStart(oCh.doWork));
Thread bThread = new Thread(new ThreadStart(oDe.doWork));
Thread cThread = new Thread(new ThreadStart(oEc.doWork));
Thread dThread = new Thread(new ThreadStart(oFo.doWork));
// Start the thread
oThread.Start();
aThread.Start();
bThread.Start();
cThread.Start();
dThread.Start();
// Spin for a while waiting for the started thread to become
// alive:
while (!oThread.IsAlive);
while (!aThread.IsAlive);
while (!bThread.IsAlive);
while (!cThread.IsAlive);
while (!dThread.IsAlive);
// Put the Main thread to sleep for 1 millisecond to allow oThread
// to do some work:
Thread.Sleep(1);
// Wait until oThread finishes. Join also has overloads
// that take a millisecond interval or a TimeSpan object.
oThread.Join();
aThread.Join();
bThread.Join();
cThread.Join();
dThread.Join();
Console.WriteLine();
Console.WriteLine("Alpha.Beta has finished");
/*
try
{
Console.WriteLine("Try to restart the Alpha.Beta thread");
oThread.Start();
}
catch (ThreadStateException)
{
Console.Write("ThreadStateException trying to restart Alpha.Beta. ");
Console.WriteLine("Expected since aborted threads cannot be restarted.");
}
*/
while(s<number)
s++;
// Request that oThread be stopped
oThread.Abort();
aThread.Abort();
bThread.Abort();
cThread.Abort();
dThread.Abort();
return 0;
}
}
I can see a number of problems with your code, but there are two main ones that will be affecting you. I've assumed that your commented out Monitor calls shouldn't be commented (else the code makes no sense).
Firstly, you create a new instance of Msg under each thread. The Beta method locks on the current instance of Msg (in the commented Monitor.Wait(this)), and so each instance is essentially waiting on itself - which will be an infinite wait, because the only Monitor.Pulse is later in the same method, and will never be reached.
Because some of your Msg instances will be created with a higher value for priority, they will skip the while loop entirely and should continue to call Monitor.Pulse, but there will be nothing waiting on that pulse.
Later in your Main method, you have the following:
while (!oThread.IsAlive) ;
while (!aThread.IsAlive) ;
while (!bThread.IsAlive) ;
while (!cThread.IsAlive) ;
while (!dThread.IsAlive) ;
This is flawed. Because there's no guarantee of the execution order of your threads, it's entirely possible for the above code to deadlock. If your oThread isn't started immediately, but dThread is scheduled and runs to completion, you could easily see a case where dThread is completed and "dead" before the final line above is reached.
All in all, I'm not clear on what your code is trying to achieve, but as it stands I'd expect it to deadlock every time.

Execute a list of threads

I have a list of a object "Code":
List<Code> listCodes = new List<Code>();
I need to execute each code inside the list in a Thread, but I have not idea how to do that, because I tried to do something like:
foreach(Code c in listCodes)
{
Thread tr = new Thread(delegate() {
Execute(c.CodeLine);
});
}
This foreach is in a timer, because those Codes will be executed all the time, but when I do that the same code is executed a lot of times even if the first execution wasn't finished, if the code takes like 5 seconds to be executed and finished and the timer is 500ms it will be executed 10 times if I disable the timer after 5 seconds for exemple.
I couldn't think anything to execute the codes in the list, each one in their thread, but I want to execute the thread of the code 0(for exemple) only if it was finished after the execution.
Thank you.
System.Threading.Monitor.TryEnter is perfect for the job:
foreach(Code c in listCodes) {
Code a = c;
new Thread(delegate() {
if(Monitor.TryEnter(a)) {
Execute(a.CodeLine);
Monitor.Exit(a);
}
}) { IsBackground = true }.Start();
}
What it does is try to acquire an exclusive lock on the Code object. If it can't (i.e. the Code is already executing) then nothing will happen; otherwise, the lock is acquired, and released when execution is complete.
I think using Threads like this is inefficient, you should use Tasks instead.
In C# 5, I would do it like this:
private static async Task RunCode(Code code, TimeSpan delay)
{
while (!Stopped)
{
var delayTask = Task.Delay(delay);
Execute(code.CodeLine);
await delayTask;
}
}
And then start it once (i.e. not in a timer):
foreach (Code c in listCodes)
{
Task.Run(() => RunCode(c, TimeSpan.FromMilliseconds(1000)));
}
You need to actually wait for the Threads to finish. You do this by calling Join:
List<Thread> threads = new List<Threads>();
foreach(Code c in listCodes)
{
Thread tr = new Thread(delegate() {
Execute(c.CodeLine);
});
threads.Add(tr);
}
foreach(Thread tr in threads)
{
tr.Join();
}
This is all inside your outer timer.

Categories