As far as I know, the variable in thread should be not safe if not locked. But I tried it on Unity, and found it different.
I try the code below:
void Awake () {
Thread thread = new Thread(new ThreadStart (demo));
thread.Start ();
for (int i = 0; i < 5000; i++) {
count = count + 1;
}
}
void demo() {
for (int i = 0; i < 5000; i++) {
count = count + 1;
}
}
And I try to Debug.Log(count), and every times I try it that is 10000. But it should be a number which is less than 10000 because of not thread safety, shouldn't it? So can anyone tell me why?
Here's an Minimal, Complete, and Verifiable example of your code:
void Main()
{
Awake();
Console.WriteLine(count);
}
private int count = 0;
public void Awake()
{
Thread thread = new Thread(new ThreadStart(demo));
thread.Start();
for (int i = 0; i < 5000; i++)
{
count = count + 1;
}
thread.Join();
}
public void demo()
{
for (int i = 0; i < 5000; i++)
{
count = count + 1;
}
}
If you run that you get 10000 out. This is because by the time the thread has started the .Awake() method has finished its loop and thus no conflict occurs.
Try changing the loops to for (int i = 0; i < 50000; i++) then the result I got for one run is 89922. It changes each time, but sometimes I still get 100000.
The thread need some time to schedule to start. The main thread might finish the increments before the other thread start. Try to use a large value like 50000000.
Related
This question already has answers here:
Captured variable in a loop in C#
(10 answers)
Closed 4 years ago.
First off, I'm new to C#, and this is the first program I've written that uses threads. Sorry if it's a bit basic.
Here's my app:
class Program
{
static void AddNumbers()
{
int count = 0;
for (int counter = 0; counter < 90000000; counter++)
{
count += counter;
}
}
static void Main()
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((i + 1).ToString());
}).Start();
}
stopwatch.Stop();
Console.WriteLine("Time elapsed: {0:hh\\:mm\\:ss}", stopwatch.Elapsed);
Console.ReadLine();
}
}
It simply loops i times and adds a bunch of numbers each time. When I run the AddNumbers() version non-multithreaded, it correctly displays 1, 2, 3... etc, but when I run it multithreaded, it returns the same indexes 2-3 times, skips some, and returns the stopwatch value before all the threads have executed.
Can someone please help spot where my error is and most of all clarify my thinking about how threads work in C#? Thanks!
When I run the AddNumbers() version non-multithreaded, it correctly displays 1, 2, 3... etc, but when I run it multithreaded, it returns the same indexes 2-3 times, skips some
It happens, because i is captured, but changed in outside loop.
Read more about it here:
Captured variable in a loop in C#
http://www.trycatchthat.com/csharp/fundamentals/2016/02/29/csharp-closure-loops.html
In order to make it work properly you need to save a local copy:
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
int iCopy = i;
new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
}).Start();
}
returns the stopwatch value before all the threads have executed
It happens, because you actually never join your threads and wait for them to execute.
It can be achieved by storing all threads and calling thread.Join():
Thread[] threads = new Thread[50];
for (int i = 0; i < 50; i++)
{
// Non-threaded
//AddNumbers();
//Console.WriteLine((i + 1).ToString());
// Threaded
int iCopy = i;
threads[i] = new Thread(() =>
{
//Thread.CurrentThread.IsBackground = true;
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
});
thread[i].Start();
}
for (int i = 0; i < 50; i++)
threads[i].Join();
Read more about waiting for threads to complete here:
Create multiple threads and wait all of them to complete
This is how people used to do it before TPL has been invented.
Now, general rule is not to use Thread, but use Task or Parallel instead.
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
Task[] tasks = new Task[50];
for (int i = 0; i < 50; i++)
{
int iCopy = i;
tasks[i] = Task.Run(() => {
AddNumbers();
Thread.Sleep(1000);
Console.WriteLine((iCopy + 1).ToString());
});
}
Task.WaitAll(tasks);
Is there a simple way to check if any threads are waiting for a specific ManualResetEvent
object to be set? It seems to me that the computer must be somehow keeping a queue of the
paused threads to restore later, so I'm just hoping to do the obvious and access
this list (just to check whether or not it is empty)...but I couldn't find a
method from looking at Microsoft's related Threading/WaitHandle/Monitor help pages.
Test code is below. I'd simply like to replace the uglyWaiters counter.
using System;
using System.Threading;
namespace demo
{
class Program
{
static void Main()
{
var gate = new ManualResetEvent(false);
int uglyWaiters = 0; // I want to stop using this variable and instead use something built into ManualResetEvent
new Thread(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("a" + i);
uglyWaiters++;
gate.WaitOne();
uglyWaiters--;
Thread.Sleep(400);
}
}).Start();
new Thread(() =>
{
for (int i = 0; i < 5; i++)
{
Console.WriteLine("b" + i);
uglyWaiters++;
gate.WaitOne();
uglyWaiters--;
Thread.Sleep(500);
}
}).Start();
for (int count = 0; count < 15; count++)
{
Console.WriteLine(uglyWaiters + " threads waiting at t=" + count*230 + "ms");
gate.Set(); Thread.Sleep(30); gate.Reset();
Thread.Sleep(200);
}
Console.ReadLine();
}
}
}
Instead of printing o and -, I want to print the number of o and - on the console. However, I have no idea how to get how many times a loop spins in a thread before it gets switched to other threads.
If there are events something likes OnLeaving and OnEntering on a thread, I can get the number of spins in the given time slice. Unfortunately, I have no such events.
class Program
{
public const int N = 1000;
static void Main(string[] args)
{
ThreadStart ts = DoWork;
Thread t = new Thread(ts);
t.Start();
for (int x = 0; x < N; x++)
{
Console.Write('o');
}
t.Join();
}
private static void DoWork()
{
for (int x = 0; x < N; x++)
{
Console.Write('-');
}
}
}
Could you show me how to do this scenario?
To reiterate: AbhayDixit's comment gives you a cycle counter. You just need to add a locking mechanism and reset the counters after a context switch.
I have modified your code to include a cycle counter. Note that I have increased N significantly. Otherwise, one thread will just run through its 1000 iterations at once - because you no longer have a Write() instruction to slow it down.
class Program
{
public const int N = 1000000;
private static object _l = new object();
private static int _i = 0;
private static int _j = 0;
static void Main(string[] args)
{
ThreadStart ts = DoWork;
Thread t = new Thread(ts);
t.Start();
for (int x = 0; x < N; x++)
{
lock (_l)
{
// j-thread has run?
if (_j > 0)
{
// print and reset j
Console.Write("j{0} ", _j);
_j = 0;
}
_i++;
}
}
t.Join();
// print remaining cycles
// one of the threads will have run after the other has finished and
// hence not been printed and reset.
if (_i > 0)
Console.Write("i{0} ", _i);
if (_j > 0)
Console.Write("j{0} ", _j);
Console.ReadKey();
}
private static void DoWork()
{
for (int x = 0; x < N; x++)
{
lock (_l)
{
// i-thread has run?
if (_i > 0)
{
// print and reset i
Console.Write("i{0} ", _i);
_i = 0;
}
_j++;
}
}
}
}
class Thread1_8
{
static int shared_total;
static int thread_count;
static readonly object locker = new object();
static void Main()
{
int[,] arr = new int[5, 5] { { 1,2,3,4,5}, {5,6,7,8,9}, {9,10,11,12,13}, {13,14,15,16,17}, { 17,18,19,20,21} };
for(int i = 0; i < 5; i++)
{
new Thread(() => CalcArray(i, arr)).Start();
}
while(thread_count < 5)
{
}
Console.WriteLine(shared_total);
}
static void CalcArray(int row, int[,] arr)
{
int length = arr.GetLength(0);
int total = 0;
for(int j = 0; j < length; j++)
{
total += arr[row,j];
}
lock (locker)
{
shared_total += total;
thread_count++;
}
}
}
I keep getting a System.IndexOutOfRangeException.
The reason is because for some reason my "i" in the initial for loop is being set to 5 and STILL entering the loop for some reason. I don't understand why. At first I thought it might be because the each thread I create is incrementing the Array but it shouldn't since a Thread has a complete separate execution path, it should jump straight to the CalcArray method.
The reason why this happens is subtle: when you do this
for(int i = 0; i < 5; i++) {
new Thread(() => CalcArray(i, arr)).Start();
}
variable i goes through values 0 all the way to 5, at which point the loop stops, because 5 < 5 evaluates to false.
The thread starts after the loop is over, so the value of row that it sees is 5, not 0 through 4.
This can be fixed by making a local variable row inside the loop.
Another problem in your code is checking thread_count inside Main without locking, in a busy loop. This is not the best process of synchronizing with your threads. Consider using ManualResetEventSlim instead.
I have been getter the error above at random times. One time the bot passess the point of collectiong 200 k links without the above than at some point it gives the error at 80 k another at 150 k etc. So it is random.
Searching the error i read that it is dues to some threads stuck in something and repeatedly calling itself causing this.
So i went through all my code but i do not see any while or other loops than can be infinite loops other than the main top one to start the threads ?
Here is the main code:First i start the threads :
for (int j = 0; j < 10; j++)
{
Console.Write("STARTING THREADS " + j);
Thread thread = new Thread(() => startPosting2());
thread.IsBackground = true;
thread.Start();
Random rnd = new Random();
int x = 0;
x = rnd.Next(1, 10);
System.Threading.Thread.Sleep(1000 * x);
}
Than the scraping :
static int rowCounter = -1;
int totalRows = 0;
static private Object thisLock = new Object();
public void startPosting2()
{
while (rowCounter < urlList.Count)
{
try
{
//List<Thread> threads = new List<Thread>();
int tmprowCounter = 0;
lock (thisLock)
{
rowCounter = rowCounter + 1;
tmprowCounter = rowCounter;
}
string url = urlList[tmprowCounter].ToString();
scrapsomething(url);
}
catch(Exception ex)
{}
}
The above is the only while loop but it get more link as it goes to total rows can be 100 when it enter the loop and can be 100k and its still in the loop as until it keeps getting links inside it keep adding to the urlList . Can this be the cause, And is it bad coding?
UPDATE
What if i change the above code to as follows :
static int rowCounter = -1;
int totalRows = 0;
static private Object thisLock = new Object();
public void startPosting2()
{
while (rowCounter < urlList.Count)
{
try
{
//List<Thread> threads = new List<Thread>();
int tmprowCounter = 0;
lock (thisLock)
{
rowCounter = rowCounter + 1;
tmprowCounter = rowCounter;
}
string url = urlList[tmprowCounter].ToString();
Thread t = new Thread(() => scrapeSiteCollectLinks(url));
t.Start();
t.Join(60000);
}
catch(Exception ex)
{}
}
Will this help ! As if any thing is getting stuck it has to quit after 60 seconds time out ? Is this logic correct?