I wan to speed up my tool with multi thread to read/write text file
Here how I start - I think I need 7 thread
for (int i = 0; i < 7; i++)
{
Thread thread = new Thread(() => process(files[i], i));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
And my func
void process(string file,int threadnumber)
{
// display thread number
// filter text
// read - write
}
But when I start:
Thread: 3 start
Thread: 3 start
Thread: 3 start
Thread: 4 start
Thread: 5 start
Thread: 6 start
Thread: 7 start
Why my tool don't start thread 1 2 3 4 5 6 7.. few threads duplicate - meaning read and write same file and error.
Please give me advise.
Depending on how fast the loop iterates and how fast a thread starts, there is a chance that by the time that a thread actually starts the i variable might have changed.
You must declare a new variable, for each thread, that is not changed:
for (int i = 0; i < 7; i++)
{
int j = i; //New variable set to the current 'i'.
Thread thread = new Thread(() => process(files[j], j));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
In the above the j-variable will get the same value as the current i, and won't change even if the loop continues to iterate.
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.
Method in thread is not executed, with thread.start();
Instead when I use thread.join() them method is executed.
Thread[] threads = new Thread[12];
int temp;
//_stopRequest = false;
for (int i = 0; i < threads.Length - 1; i++)
{
temp = i;
threads[temp] = new Thread(new ThreadStart(() => test(test1[temp],"start", temp)));
threads[temp].Start();
//threads[temp].Join();
}
Could anyone please shed light on this.
Trying to start all threads at the same time
Try to add
for(int i=0; i<threads.Length-1; i++)
{
threads[i].Join();
}
at the end of the method. Your threads will start at the same time, and you will wait for their ending. Other variant: set their IsBackground property to true. So, your program will not finish until these threads finish their work.
P.S. In your loop use "int temp = i;", if you want to work with closures. In your case, all threads closure to the same variable temp.
What I want to do
I have some threads (e.g. Thread 1, Thread 2, Thread 3), and a queue of integers (e.g. 1, 2, 3).
Every one second, I want to pause currently running thread, and pop from a queue, and run a thread that has the same id.
For example:
Let's say I have an array of thread, and an integer that holds currently executing thread.
int[] myThread; //1, 2, 3
ManualResetEventSlim[] mre;
executing = 1;
Queue myQueue; //2, 3
Time 0:01 //Thread 1 is running
Time 0:02 mre[executing].Wait();
myQueue.Enqueue(executing);
int nextThread = myQueue.Dequeue(); //say 2
mre[nextThread].Set();
executing = nextThread;
Time 0:03 //Same thing as at 0:02...
Time 0:04 //Same above
Time 0:05 //Same above
and want outputs that look like this:
Time 0:01 I'm 1
I'm 1
I'm 1
Time 0:02 I'm 2 // thread 2 was selected
I'm 2
I'm 2
Time 0:03 I'm 3 // thread 3 was selected
I'm 3
I'm 3
Time 0:04 I'm 2 // thread 2 was selected
I'm 2
I'm 2
What I'm doing
I have a main file that defines the action:
static void Main()
{
CreateThread(Action, n);
}
public static void Action(int pid)
{
for(int i=0; i<100000; i++)
{
Trace.WriteLine("I'm "+ pid);
}
}
Problem
The problem is that once a thread is set with Set(), it cannot be blocked again with Wait(). Because of that, each thread just keeps executing the whole Action method until it's done.
and outputs look like this:
Time 0:01 I'm 1 //Only Thread 1 is unblocked
I'm 1
I'm 1
Time 0:02 I'm 2 //Thread 2 was unblocked.
I'm 1 //Thread 1 is not blocked, so it keeps printing
I'm 2
Time 0:03 I'm 3 //Thread 3 was unblocked.
I'm 1 //Thread 1 is not blocked
I'm 2 //Thread 2 is not blocked either
I've been working on this for a while and am stuck. I really appreciate any help.
Im not sure if I understand the problem, but I'd change Action() so that it takes an instance of ThreadData. You'll need it to check whether the MRE is set. If so, break out of the iteration and let the framework take care of cleaning up after the thread.
public static void Action(ThreadData threadData)
{
for (int i = 0; i < 100000; i++)
{
if (threadData.Mre.IsSet)
{
break;
}
Trace.WriteLine("I'm " + threadData.Pid);
}
}
EDIT
You might not realize it, but you're probably using the same instance of MRE for each thread. Each thread references the mre variable. Who is to say that the thread starts before you set mre to a new instance? Spoiler: it doesn't.
This is a slightly modified version of one of the sample programs give in C# in a Nutshell :
using System;
using System.Threading;
namespace SemaphorTest
{
class Program
{
static Semaphore gate = new Semaphore(3, 3);
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(Enter);
t.Start(i);
}
}
public static void Enter(Object id)
{
Console.WriteLine("Thread " + id + " wants to enter.");
gate.WaitOne();
Console.WriteLine("Thread " + id + " is in.");
Thread.Sleep(500 * (Int32)id);
Console.WriteLine("Thread " + id + " leaving.");
gate.Release();
}
}
}
This prints the following output (seemingly in random order) :
Thread 0 wants to enter.
Thread 1 wants to enter.
Thread 1 is in.
Thread 0 is in.
Thread 2 wants to enter.
Thread 3 wants to enter.
Thread 0 leaving.
Thread 3 is in.
Thread 4 wants to enter.
Thread 2 is in.
Thread 1 leaving.
Thread 4 is in.
Thread 2 leaving.
Thread 3 leaving.
Thread 4 leaving.
However, adding a Thread.Join() as follows changes the output drastically.ie:
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(Enter);
t.Start(i);
t.Join();
}
Changes the output to :
Thread 0 wants to enter.
Thread 0 is in.
Thread 0 leaving.
Thread 1 wants to enter.
Thread 1 is in.
Thread 1 leaving.
Thread 2 wants to enter.
Thread 2 is in.
Thread 2 leaving.
Thread 3 wants to enter.
Thread 3 is in.
Thread 3 leaving.
Thread 4 wants to enter.
Thread 4 is in.
Thread 4 leaving.
Why does this happen ? I know that these threads are foreground threads by default and that the Main thread doesn't need to wait for them to complete (they will run even after Main completes so they won't require a thread.Join() here). But I don't understand what makes them run in the order as they were created after the change. Any ideas ?
Thanks
Dileep Balakrishnan
Why does this happen?
Because you've asked it to!
You've started one thread, then waited for it to finish, then started the next thread etc. That's precisely what Thread.Join does: it blocks the currently executing thread until the thread you've called it on terminates.
What I'm interested in is what you expected that code to do... If you just wanted to wait until all the threads had finished before letting the main thread complete, you need to start all the threads, remembering them as you go, and then call Join on each on in turn. For example:
List<Thread> threads = new List<Thread>();
// First start all the threads
for (int i = 0; i < 5; i++)
{
Thread t = new Thread(Enter);
t.Start(i);
threads.Add(t);
}
// Then wait for them to finish
foreach (var thread in threads)
{
thread.Join();
}
You are joining each thread with the calling thread. This will essentially block the calling thread and wait for each thread to end in turn.
In the documentation it states:
Blocks the calling thread until a thread terminates.
Thread.join() does not make things run concurrently. It actually enforces the behaviour you're seeing by blocking the current thread until it's completed.
This is mentioned clearly in the documentation: http://msdn.microsoft.com/en-us/library/95hbf2ta.aspx
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));
}
}