I read a lot of answers on this point but I did not found the solution yet.
I have a class with a counter attribute having a problem with cached values. Even volatile don't seems to work:
public class MyClass {
private Timer _timer;
private int _threadsCounter = 0;
public StreamWriter Tracer { get; set; }
public MyClass() {
_timer = new Timer(1000.0 * 10);
_timer.AutoReset = true;
_timer.Elapsed += new ElapsedEventHandler(OnTimer);
_timer.Start();
}
private void OnTimer(object sender, ElapsedEventArgs e) {
HashSet<Task> taskPool = new HashSet<Task>();
try {
if (Tracer != null) Tracer.WriteLine("[{0}] onTimer start. Current threads counter is {1}.", DateTime.Now, _threadsCounter);
if (_threadsCounter >= 10) return;
// create parallel tasks
for (int i = 0; i < 8; i++) {
// limit on the max num of parallel processing but the counter remains unchanged during this timer event!!!
if (_threadsCounter >= 10) break;
var timeout = (30 + i * 2);
var task = Task.Run(() => {
var localCounter = System.Threading.Interlocked.Increment(ref _threadsCounter);
try {
System.Threading.Thread.Sleep(timeout * 1000);
}
finally {
System.Threading.Interlocked.Decrement(ref _threadsCounter);
}
});
taskPool.Add(task);
}
}
finally {
if (Tracer != null)
Tracer.WriteLine("[{0}] onTimer end. Created {1} tasks. Current threads counter is {2}.", DateTime.Now, taskPool.Count, _threadsCounter);
}
}
Well, it seems that the onTimer caches the _threadsCounter variable as the output is:
[14:10:47] onTimer start. Current threads counter is 0.
[14:10:47] onTimer end. Created 8 tasks. Current threads counter is 0.
[14:10:57] onTimer start. Current threads counter is 8.
[14:10:57] onTimer end. Created 8 tasks. Current threads counter is 8.
[14:11:07] onTimer start. Current threads counter is 16.
[14:11:07] onTimer end. Created 0 tasks. Current threads counter is 16.
[14:11:17] onTimer start. Current threads counter is 15.
[14:11:17] onTimer end. Created 0 tasks. Current threads counter is 15.
[14:11:37] onTimer start. Current threads counter is 4.
[14:11:37] onTimer end. Created 8 tasks. Current threads counter is 4.
[14:11:47] onTimer start. Current threads counter is 8.
[14:11:47] onTimer end. Created 8 tasks. Current threads counter is 8.
[14:11:57] onTimer start. Current threads counter is 16.
[14:11:57] onTimer end. Created 0 tasks. Current threads counter is 16.
Why do I arrive to 16?
I solved the problem by changing a bit the code:
var localCounter = _threadsCounter;
...
if ((localCounter + taskPool.Count) >= 10) break;
But why this behavior?
Task.Run doesn't start the task immediately. It adds the task to the thread pool queue and returns.
In your case, the whole for loop is executed before the new tasks start running, so nothing changes _threadsCounter. That's why volatile doesn't help.
You're effectively testing for the number of tasks that have actually started and got as far as incrementing the counter. That takes a little while - so basically you're creating all 8 tasks and starting them, then they're incrementing the counter... by which time it's too late to notice that you've got more than 10.
The better solution would be to increment the counter before you start the task:
// Increment the counter in expectation of starting a task
var localCounter = Interlocked.Increment(ref _threadsCounter);
if (localCounter >= 10)
{
// Ah, we're not going to start a task after all, so undo
// the increment
Interlocked.Decrement(ref _threadsCounter);
break;
}
else
{
// Start a task, which will decrement the counter at the end.
// (You could add the "decrement" bit as a continuation, even...)
}
Related
I test simple code
static Thread _readThread = null;
static private Object thisLock = new Object();
static int a = 1;
private static void ReadComPort()
{
lock (thisLock)
{
for (int i = 0; i < 3; i++)
{
Console.WriteLine(Thread.CurrentThread.Name + " " + a++.ToString());
Thread.Sleep(1000);
}
}
}
static void Main(string[] args)
{
for (int i = 0; i < 3; i++)
{
_readThread = new Thread(new ThreadStart(ReadComPort));
_readThread.IsBackground = true;
_readThread.Name = i.ToString();
_readThread.Start();
//Thread.Sleep(50);
}
Console.WriteLine("End");
Console.ReadKey();
}
but why is the sequence of execution and the launching of threads chaotic:
0,2,1 Why?
Console output:
0 1
End
0 2
0 3
2 4
2 5
2 6
1 7
1 8
1 9
Because you can't expect threads to start or run in a specific order. The OS schedules threads the way it wants to. Sometimes it puts a thread on hold, executes another one, before coming back to the original one.
Here you see that the threads start almost at the same time. Obviously (from the output) thread 0 wins it to the first lock. Then, by pure chance, thread 2 gets by the lock earlier than thread 1. This could have gone entirely different since the threads are created shortly after each other. As said: there is no guarantee.
Lock does not guarantee the order : Does lock() guarantee acquired in order requested?
Also, in your code, you should wait your threads to finish at the end of your for loop in order to not have "end" at the beginning - if you press a key, you will exit while your thread are still running, and you may have unexpected behaviour.
Read the C# reference carefully.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement
There, you cannot find anything about the order of threads entering the lock block.
I have a BlockingCollection of integers.
Below is the code I am trying to develop to remove the items concurrently from the BlockingCollection.
static void Produce()
{
for (int i = 0; i < 100000; i++)
{
bc3.Add(i);
}
Run();
}
static void Run()
{
for (int i = 0; i < 5; i++)
{
Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning);
}
}
static void Process()
{
var stopWatch = new Stopwatch();
stopWatch.Start();
while (bc3.Count!= 0)
{
bc3.Take();
}
stopWatch.Stop();
Console.WriteLine("Thread {0}",
Thread.CurrentThread.ManagedThreadId);
Console.WriteLine("Elapsed Time {0}", stopWatch.Elapsed.Seconds);
}
Is this the correct way remove items in a faster way by creating 5 tasks?
Stopwatch issue
Your measurement results are wrong because you use
stopWatch.Elapsed.Seconds
instead of
stopWatch.ElapsedMilliseconds
You only display the seconds, but ignore the minutes, hours, etc.
Concurrency issue
No, this is not the correct way of removing items from a BlockingCollection. The statement that does not work is
bc3.Count != 0
All 5 tasks may check this condition at the same time, finding out that there is 1 item left. They all 5 go to
bc3.Take();
One task is able to remove the item, the other 4 tasks are waiting.
One way to solve this is to add
bc3.CompleteAdding();
in Produce().
Garbage collection issue
Once the first task finishes, the Run() method completes and all tasks in the method go out of scope and are garbage collected. This may make you see only 1 instead of 5 completion messages.
To fix this, use
static void Run()
{
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning));
}
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException)
{ }
}
Cost of synchronization
Here's one of my outputs with 5 tasks (and 100000000 items):
Thread 11
Thread 13
Thread 12
Thread 14
Thread 15
Elapsed Time 12878
Elapsed Time 13122
Elapsed Time 13128
Elapsed Time 13128
Elapsed Time 13128
Run: 13140
Compare this to a single task:
Thread 12
Elapsed Time 10147
Run: 10149
This is because only one Take() method can remove an item and it takes additional time for synchronization.
I have to loop through code for specified time .I achieved it with DateTime
var time=DateTime.Now.AddMinutes((Convert.ToDouble(1)));
while(DateTime.Compare(DateTime.Now, time) <= 0)
{
console.write("some message..")
}
How do i achieve the same with Timer.Timer or thread.timer which is best approach..
Is it possible to write 10 times per sec?
Can anyone suggest. thank you
You could always use StopWatch, which is accurate and most appropriate for your scenario.
Action<long> action = (milliseconds) =>
{
Console.WriteLine("Running for {0}ms", milliseconds);
Stopwatch watch = new Stopwatch();
watch.Start();
while (watch.Elapsed.TotalMilliseconds <= milliseconds)
{
Console.WriteLine("ticks:{0}", DateTime.Now.Ticks);
Thread.Sleep(100);
}
Console.WriteLine("Done");
watch.Stop();
};
Task.Run(() => action(1000));
if you are going to make this work you need to make your program multithreaded,
See System.Threading and System.Threading.Task
Once you have your code executing in it's own thread, (using Thread, Task, Timer or any of the other variations in those namespaces) you can tell it to stop executing for a set amount of time, this is done by calling the Thread.Sleep or Task.Delay methods.
e.g.
Task.Run(()=>
{
do
{
//do something
await Task.Delay(100);
}
while(! exitCondition)
});
however you shouldn't count on this for exact timing as what you are doing is saying to the OS that this thread doesn't need to be executed for that amount of time, it doesn't mean the OS will pass it to the processor immediately on the time running out. depending on how busy the CPU is there can be quite a delay before your thread reaches the top of the waiting to process queue. if the timing is vitally important then i would set a lower time and check the clock before running
static void Main(string[] args)
{
System.Threading.Timer timer = null;
int counts = 0;
timer = new Timer((obj) =>
{
Console.WriteLine(counts);
if (++counts > 10)
timer.Dispose();
}, null, 100, 100);
for (;;) ;
}
will call the method dosomething() after 100ms, every 100ms
in the background, till timer.Dispose() is called;
this implementation will ofc never terminate as it is written here ;)
I have a c# windows service with a timer that executes a process every 5 minutes.
I don't want to create other process to execute a task every 30 minutes, so is it possible within the same timer timer_Elapsed event to do that logic? any clue?
Thanks a lot,
How about using 2 timers?
You could increment a variable every time the timer elapses, and when that variable reaches 6, you reset it to 0 and execute your 'once every 30 minute' code. Also, creating a new (winform) timer does not create a new thread as far as I know.
int TimerVariable=0;
TimerEvent(object sender,eventargs e)
{
TimerVariable++;
if(TimverVariable>=6)
{
//Execute the once every 30 min code
}
//Execute the once every 5 min code.
}
Well, you could just use a counter and check it against 6(30000/5000) and reset it back to zero when done.
private int counter = 0;
private void TimerCallback()
{
counter++;
if(counter >=6)
{
//Your 30 seconds code here
counter = 0;
}
}
im trying to use few threads to make the following:
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 5; i++)
threads.Add(new Thread(CheckTradeOneForOne));
foreach (Thread t in threads)
t.Start();
progressBarTrades.Value = 0;
count = 0;
while count is defined at class-level,and progressbar is progressbar(winforms^_^).
private void CheckTradeOneForOne()
{
int current;
while (count < Trades.Count)
{
lock (locker)
{
current = count;
count++;
}
temppage = HelpClass.GetSourceCodeForTrade(Trades[current], sessid, profilenum);
//if the trainer has requested anything?
if (!HelpClass.RequestAnything(temppage))
{
}
lock (locker)
{
progressBarTrades.Value = (100 * count) / Trades.Count;
//buttonAction.Text = count.ToString();
}
}
}
Trades is List(length around 1000).
i want to pass of all the trades and make one httpwebrequest each,
therefore i want to use multithreading,
the problem is that although i use lock im getting error about the second lock that another thread is using buttonaction\progressbar.
one more thing, is this a proper way to use multithreading?
how much threads is ideal to use?
and do the lock make sure that no moe then one thread take the same trade string?
tyvm for your help:)
With windows form the best way to work with the progress bar and threads is BackgroundWorkers in MSDN is a good example.
You cannot access windows form or wpf controls from a thread that is not the form thread.
To do that you should use BeginInvoke or the class SynchronizationContext.
However since you are just updating a progressbar I would suggest you to use a simple timer, if you have a lot of threads, it will be faster.
Instead threads I would also suggest you to use ThreadPool, this will avoid the instantiation of too many threads.
Just as an example I post some code.
private volatile int TradesCount;
private List<...> Trades;
void MyFunction()
{
List<Thread> threads = new List<Thread>();
for (int i = 0; i < 5; i++)
threads.Add(new Thread(CheckTradeOneForOne));
timer1.Enabled = true;
progressBarTrades.Value = 0;
this.TradesCount = 0;
foreach (Thread t in threads)
t.Start();
}
void timer1_Tick(object sender, EventArgs e)
{
int count = this.TradesCount;
if (count >= Trades.Count)
{
count = Trades.Count;
timer1.Enabled = false;
}
progressBarTrades.Value = (100 * count) / Trades.Count;
buttonAction.Text = count.ToString();
}
private void CheckTradeOneForOne()
{
int current;
for (;;)
{
// This will give you a warning, but you can ignore it with a #pragma, it is allowed to use Interlocked.Increment and volatile fields.
current = Interlocked.Increment(ref TradesCount) - 1;
if (current >= Trades.Count)
break; // We can exit the loop.
temppage = HelpClass.GetSourceCodeForTrade(Trades[current], sessid, profilenum);
//if the trainer has requested anything?
if (!HelpClass.RequestAnything(temppage))
{
...
}
}
}
I'm using Interlocked.Increment instead of lock, it is faster.
Look on google about Interlocked.Increment, it is a very good function: atomic increment.
I agree with the other answers recommending the use of .NET thread-pool instead of starting new threads yourself. If you have the luxury of using .NET 4 or newer, I would go even further and recommend you use the Task Parallel Library (and even if you are not currently using .NET 4, building a task-oriented abstraction on top of .NET thread-pool is very simple).
One of the biggest advantages of using tasks IMHO is that they are the foundation of the coming C# 5 await built-in language feature. So if you use tasks for your background processing today, you are already preparing your program for the future :-).
To show how you can use tasks to solve your immediate problem, I wrote a simple WinForms program that illustrates the technique of doing background processing and updating a progress bar to track how many tasks have already finished:
// file "Program.cs"
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ProgressDialog
{
static class Program
{
[STAThread] static void Main()
{
// build UI
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var rootForm = new Form { Text = #"Test Form", Width = 300, Height = 100 };
var btn = new Button { Text = #"Start", Parent = rootForm, Dock = DockStyle.Top };
var progress = new ProgressBar { Minimum = 0, Parent = rootForm, Dock = DockStyle.Top, Style = ProgressBarStyle.Continuous };
new Label { Text = #"Progress:", Parent = rootForm, Dock = DockStyle.Top, AutoSize = true };
// define parameters
const int sourcesCount = 20; // how many sources do we want to process
var completedCount = 0;
var randomGenerator = new Random();
var timer = new Stopwatch();
// callback that will be invoked on UI thread each time a task finishes
Action<int> onTaskCompleted = source =>
{
++completedCount; // we're modifying "completedCount" closure on purpose
progress.Value = completedCount;
System.Diagnostics.Debugger.Log(0, null, string.Concat(#"UI notified that task for source ", source, #" finished; overall ", completedCount, #" tasks finished", Environment.NewLine));
if (completedCount == sourcesCount)
{
timer.Stop();
btn.Enabled = true;
btn.Text = string.Concat(#"Finished (took ", timer.ElapsedMilliseconds, #" milliseconds). Start again");
}
};
// task itself (the hard part :) )
Action<int> task = source =>
{
System.Diagnostics.Debugger.Log(0, null, string.Concat(#" > Starting task for source ", source, Environment.NewLine));
Thread.Sleep(randomGenerator.Next(100, 200)); // simulate some workload (taking between 100 and 200 milliseconds)
System.Diagnostics.Debugger.Log(0, null, string.Concat(#" < Finished task for source ", source, Environment.NewLine));
rootForm.BeginInvoke(new Action(() => onTaskCompleted(source)));
};
// start button handler (kick-starts the background tasks)
btn.Click += (src, args) =>
{
btn.Enabled = false;
btn.Text = #"Running...";
progress.Maximum = sourcesCount;
progress.Value = 0;
timer.Restart();
completedCount = 0;
var sources = Enumerable.Range(1, sourcesCount); // simulate getting data for each task
var tasks = sources
.Select(s => Task.Factory.StartNew(() => task(s))) // at this point we only have an enumerable that is able to start all the tasks, nothing is running yet
.ToArray(); // now the tasks are started
if (tasks.Length != sourcesCount) { throw new InvalidOperationException(); } // assert that we created one task for each source
};
// show the form now, let the user interact with it
Application.Run(rootForm);
}
}
}
You can compile the program by either creating a new (console or winforms) project in Visual Studio and copying the code to Program.cs or by using the csc.exe on a command line.
When tasks are running, progress bar tracks number of finished tasks:
When all the tasks are finished, start button displays overall time taken:
Note that the time taken by each task is random (between 100 and 200 milliseconds), and number of tasks running concurrently will depend on how many processors/cores you have available (Task Parallel Library does this automatically), so the time displayed will vary between runs.
Also note that diagnostic messages are sent to the "Output" view in Visual Studio when running the program in debug mode (or you can use the SysInternals DebugView to see them). One sample run on my (2-core) machine produced the following:
> Starting task for source 1
> Starting task for source 2
> Starting task for source 3
< Finished task for source 3
> Starting task for source 4
UI notified that task for source 3 finished; overall 1 tasks finished
< Finished task for source 2
> Starting task for source 5
UI notified that task for source 2 finished; overall 2 tasks finished
< Finished task for source 1
> Starting task for source 6
UI notified that task for source 1 finished; overall 3 tasks finished
< Finished task for source 4
> Starting task for source 7
UI notified that task for source 4 finished; overall 4 tasks finished
< Finished task for source 5
> Starting task for source 8
UI notified that task for source 5 finished; overall 5 tasks finished
< Finished task for source 6
> Starting task for source 9
UI notified that task for source 6 finished; overall 6 tasks finished
< Finished task for source 8
> Starting task for source 10
UI notified that task for source 8 finished; overall 7 tasks finished
< Finished task for source 7
> Starting task for source 11
UI notified that task for source 7 finished; overall 8 tasks finished
< Finished task for source 9
> Starting task for source 12
UI notified that task for source 9 finished; overall 9 tasks finished
< Finished task for source 10
< Finished task for source 11
> Starting task for source 13
UI notified that task for source 10 finished; overall 10 tasks finished
UI notified that task for source 11 finished; overall 11 tasks finished
> Starting task for source 14
< Finished task for source 14
> Starting task for source 15
UI notified that task for source 14 finished; overall 12 tasks finished
< Finished task for source 13
> Starting task for source 16
UI notified that task for source 13 finished; overall 13 tasks finished
< Finished task for source 12
> Starting task for source 17
UI notified that task for source 12 finished; overall 14 tasks finished
< Finished task for source 16
> Starting task for source 18
UI notified that task for source 16 finished; overall 15 tasks finished
< Finished task for source 15
UI notified that task for source 15 finished; overall 16 tasks finished
> Starting task for source 19
< Finished task for source 17
UI notified that task for source 17 finished; overall 17 tasks finished
< Finished task for source 18
> Starting task for source 20
UI notified that task for source 18 finished; overall 18 tasks finished
< Finished task for source 19
UI notified that task for source 19 finished; overall 19 tasks finished
< Finished task for source 20
UI notified that task for source 20 finished; overall 20 tasks finished
As already mentioned by some, then use the ThreadPool instead of creating the threads yourself. By using the ThreadPool you don't have to worry about the number of threads to spawn - the ThreadPool will do that for you.
Assuming you're using .NET 4, you could take advantage of TPL:
public partial class Form1 : Form
{
private volatile int count;
private readonly int total;
public Form1()
{
InitializeComponent();
var urls = new List<string> { "http://something.com", "http://another.com" };
total = urls.Count;
// Execute the Parallel loop in a thread from the threadpool,
// in order not to block the UI thread.
ThreadPool.QueueUserWorkItem(o =>
{
Parallel.ForEach(urls, x => MakeRequest(x));
});
// other UI stuff here?
}
public void MakeRequest(string url)
{
// code for web request here...
int newCount = Interlocked.Increment(ref count);
Invoke(new Action(() => progressBar.Value = (100 * newCount) / total));
}
}