473,238 Members | 1,796 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,238 software developers and data experts.

Threading - issues

Hi!

I've done some code using threading just to check if writing code improperly
can cause serious issues when using somehow safe data types.

So in my understanding a stack ( collection type ) won't give any item more
than once. But it does !!!

Again I wrote this code improperly to see what happens but I don't
understand why it happens so if you understand the issue only than reply ;)

private void btnTestThreading_Click(object sender, EventArgs e)
{
Stack<intnumbersStack = new Stack<int>();
for (int i = 0; i < 100; i++)
numbersStack.Push(i);

for (int i = 0; i < 10; i++)
{
Thread th = new Thread(delegate()
{
// i'm putting this as a reference so it should be
shared nicely
TestThreading(ref numbersStack, i);
}
);

th.Start();
}
}

private void TestThreading(ref Stack<intnumbers, int threadNumber)
{
for (int i = 0; i < 10; i++)
{
Thread.Sleep(numbers.Peek() * 10);
Console.WriteLine("Thread with number " + threadNumber +
"\t\t processed item " + numbers.Pop());
}
}
In my understanding the worst case scenario here would be 2 threads
accessing stack in the same time ( i'm not using any locks ) and than the
same item would be 'processed' twice. But what happens is 1 thread is getting
the same item twice...
HOW it's possible ? I would understand if it was other thread but it's the
same one. If you delete Thread.Sleep it stops ( at least at mine ;)

Thanks
Jedrzej

Jun 27 '08 #1
12 1380
I suspect you are victim of "captured variables" on "i";
try the following:

for (int i = 0; i < 10; i++)
{
int tmp = i; // **THIS IS IMPORTANT
Thread th = new Thread(delegate()
{
TestThreading(ref numbersStack, tmp);
}
);

th.Start();
}

I believe they were different threads, but with the same identifer ;-p

I can explain in a second (just got "visited" by someone)

Marc
Jun 27 '08 #2
I believe they were different threads, but with the same identifer ;-p
>
And you was right ;)
Could you explain how this happens that 2 diffrent threads accessing same
reference in this case stack are getting same results.
When 1 object invokes Pop() it should remove an item from the stack they are
accessing same place in the memory... There is probably a silly explanation
:)
I need an explanation of how it works to get better understanding :)

Thanks
Jedrzej
Jun 27 '08 #3
On May 30, 12:22 pm, Jarod <Ja...@discussions.microsoft.comwrote:
I believe they were different threads, but with the same identifer ;-p

And you was right ;)
Could you explain how this happens that 2 diffrent threads accessing same
reference in this case stack are getting same results.
When 1 object invokes Pop() it should remove an item from the stack they are
accessing same place in the memory... There is probably a silly explanation
:)
I need an explanation of how it works to get better understanding :)
Well, does Stack claim to be thread-safe? Most .NET collections don't
make that claim - if you access the same collection from multiple
threads with no locking, I'd expect to see some oddness. Do you get
the same issues when you obtain a lock while looking at the
collection?

Also, I think you have some misunderstandings about what "ref" does -
see http://pobox.com/~skeet/csharp/parameters.html

Jon
Jun 27 '08 #4
Well, does Stack claim to be thread-safe? Most .NET collections don't
make that claim - if you access the same collection from multiple
threads with no locking, I'd expect to see some oddness. Do you get
the same issues when you obtain a lock while looking at the
collection?
Jon,

I have problem with understanding how it's possible that using reference I
can get same element from stack twice when definition of the stack says it's
impossible.
I don't understand what exactly happens when 2 threads are accessing exactly
the same object which is reference and than they are trying to invoke method
Pop() which gives you an element and deletes it! So it looks like some other
thread was able to get the same element before deleting it. I'm just trying
to understand how it's possible.

Congrats on your book :)
Jedrzej
Jun 27 '08 #5
Jarod wrote:
>Well, does Stack claim to be thread-safe? Most .NET collections don't
make that claim - if you access the same collection from multiple
threads with no locking, I'd expect to see some oddness. Do you get
the same issues when you obtain a lock while looking at the
collection?

Jon,

I have problem with understanding how it's possible that using reference I
can get same element from stack twice when definition of the stack says it's
impossible.
I don't understand what exactly happens when 2 threads are accessing exactly
the same object which is reference and than they are trying to invoke method
Pop() which gives you an element and deletes it! So it looks like some other
thread was able to get the same element before deleting it. I'm just trying
to understand how it's possible.

Congrats on your book :)
Jedrzej
Let's assume the Pop method of the Stack class does the following:

1. Read the top element into a local variable
2. Remove the top element from its internal list
3. Return the element it read

If two threads manage to execute step 1 at the same time before neither
is at step 2, then both threads will of course see the same object.

In addition, depending on how Pop is implemented, if one of the threads
manage to run step 2 to completion before the other thread started step
2, these two threads might end up both seeing the same object, and also
removing the top two objects, one of which won't be seen by any thread.

--
Lasse Vågsæther Karlsen
mailto:la***@vkarlsen.no
http://presentationmode.blogspot.com/
PGP KeyID: 0xBCDEA2E3
Jun 27 '08 #6
On May 30, 6:49*am, Marc Gravell <marc.grav...@gmail.comwrote:
I suspect you are victim of "captured variables" on "i";
try the following:

* * * * * * *for (int i = 0; i < 10; i++)
* * * * * * *{
* * * * * * * * *int tmp = i; // **THIS IS IMPORTANT
* * * * * * * * *Thread th = new Thread(delegate()
* * * * * * * * * * *{
* * * * * * * * * * * * *TestThreading(ref numbersStack, tmp);
* * * * * * * * * * *}
* * * * * * * * *);

* * * * * * * * *th.Start();
* * * * * * *}

I believe they were different threads, but with the same identifer ;-p

I can explain in a second (just got "visited" by someone)

Marc
Tricky indeed :)
Jun 27 '08 #7
On May 30, 8:16*am, "Jon Skeet [C# MVP]" <sk...@pobox.comwrote:
On May 30, 12:22 pm, Jarod <Ja...@discussions.microsoft.comwrote:
I believe they were different threads, but with the same identifer ;-p
And you was right ;)
Could you explain how this happens that 2 diffrent threads accessing same
reference in this case stack are getting same results.
When 1 object invokes Pop() it should remove an item from the stack theyare
accessing same place in the memory... There is probably a silly explanation
:)
I need an explanation of how it works to get better understanding :)

Well, does Stack claim to be thread-safe? Most .NET collections don't
make that claim - if you access the same collection from multiple
threads with no locking, I'd expect to see some oddness. Do you get
the same issues when you obtain a lock while looking at the
collection?

Also, I think you have some misunderstandings about what "ref" does -
seehttp://pobox.com/~skeet/csharp/parameters.html

Jon
Worth to notice is the existence of a method Synchronized in several
collections ( Queue, Stack, ArrayList) that wrap the collection in a
synced version (of course you always have to access it throught the
synced one)

So to get a multithread safe Stack you can do

Stack s = Stack.Synchronized( new Stack() );

Jun 27 '08 #8
On May 30, 9:21*am, Jarod <Ja...@discussions.microsoft.comwrote:
Well, does Stack claim to be thread-safe? Most .NET collections don't
make that claim - if you access the same collection from multiple
threads with no locking, I'd expect to see some oddness. Do you get
the same issues when you obtain a lock while looking at the
collection?

Jon,

I have problem with understanding how it's possible that using reference I
can get same element from stack twice when definition of the stack says it's
impossible.
I don't understand what exactly happens when 2 threads are accessing exactly
the same object which is reference and than they are trying to invoke method
Pop() which gives you an element and deletes it! So it looks like some other
thread was able to get the same element before deleting it. I'm just trying
to understand how it's possible.

Congrats on your book :)
Jedrzej
Hi,

Very easy indeed,
do this. make two sequences of how an item is returned from the stack,
assume this operations
1- call to pop
2- asssign elem to temp var
3- delete from list
4- return elem

now, what happen if two threads are at step 2 at the same time????
Jun 27 '08 #9
Could you explain how this happens that 2 diffrent threads accessing same
reference in this case stack are getting same results.
Sorry - I got side-tracked.
The 2 different threads getting the same item is what we expect
without synchronization (actually, the whole thing could just explode
in a huge exception). The other respondants have already covered this
in plenty of detail.

The issue with your original code giving multiple threads the same id
is (as mentioned) a side-effect of "captured variables". Jon covers it
well in section 5.5 of "C# in Depth", but a brief version is that
"there is only 1 i"... even inside the ThreadStart they are all the
same variable*. By declaring "tmp" /inside/ the brace, its capture is
scoped by the brace - so each iteration of the "for" loop has a /
different/ tmp**.
This behaviour is a side-effect of capturing the variable in an
anonymous method / lambda. And it only bites when doing things like
threading, or passing the delegate outside of the method.

Marc

*=actually a field on an instance of a compiler-generated class
**=actually, a different instance of the compiler-generated class,
hence separate fields
[see I told you it was complex...]
Jun 27 '08 #10
Fascinating,

So in short, it looks like when the compiler noticed that the temp
variable was inside the loop, it went on and created a compiler
generated class where the anonymous function and temp variable
reside.

During execution, the compiler instantiated this class once per
iteration saving the temp value there.

Finally the thread calls the anonymous method on that instance using
the temp value.

Sweeeeeeet, at first, I thought that the code wouldnt work because I
didnt know the compiler was going to instantiate the compiler
generated class one time *per* iteration.

So the question that begs to be asked is (at least I am begging!)..
What triggers the compiler to create and instantiate the class one
time per iteration??? I wanted to see what would happen if I created
my own loop so I change the code as follows:

int j = 0;
LoopLabel:

int temp = j;
Thread th = new Thread(delegate()
{
TestThreading(numbersStack, temp);
}
);

th.Start();

if (++j < 10)
goto LoopLabel;

That didnt work, so I went ahead and added scope brackets to see what
would happen and it worked, see code below:

int j = 0;
LoopLabel:
{
int temp = j;
Thread th = new Thread(delegate()
{
TestThreading(numbersStack, temp);
}
);

th.Start();

if (++j < 10)
goto LoopLabel;
}

I guess the compiler figure out that the label was causing a loop to
happen so it did the right thing.

Well, I realize that what I am doing its kind of pointless but for
some reason I find this very interesting, can someone point me to the
document that would spell out what triggers the compiler to act
differently for the different scenarios? Probably the ECMA document
somewhere on page 154,534,665 :)

Anyone wanting to share any interesting experiences regarding
captured variables?

Thanks.
Rene
Jun 27 '08 #11
On Fri, 30 May 2008 14:08:09 -0700, <qg**********@mailinator.comwrote:
[...]
I guess the compiler figure out that the label was causing a loop to
happen so it did the right thing.
The compiler doesn't care about the label at all. It's the fact that a
new scope, defined by the braces, is entered that's relevant. Every time
the code enters a new level of scoping, variables declared within that
scope are considered "new" with respect to capturing.
Well, I realize that what I am doing its kind of pointless but for
some reason I find this very interesting, can someone point me to the
document that would spell out what triggers the compiler to act
differently for the different scenarios? Probably the ECMA document
somewhere on page 154,534,665 :)
I didn't look it up in the ECMA document, but in the most recent C# 3.0
specification (why there's not an ECMA spec yet I don't know), it's
documented in section 7.14.4.2, "Instantiation of local variables". The
instantiation rules are what cause local variables that are captured to be
reinstantiated within a scope that's re-entered, but not otherwise.
Anyone wanting to share any interesting experiences regarding
“captured variables”?
No, not really. :) Actually, other than the fact that it's a reasonably
common error to fail to take into account the capturing and instantiation
rules, I don't have any personal experience that might be considered
"interesting".

Pete
Jun 27 '08 #12
As Peter mentions, it is the "scope" that matters (braces in this
case). Jon's book gives a lot more detail - worth picking up a copy ;-
p Chapter 5 (which covers this) isn't one of the freebies ones,
though...

Marc
Jun 27 '08 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

13
by: Varun | last post by:
Hi Friends, Department of Information Technology, Madras Institute of Technology, Anna University, India is conducting a technical symposium, Samhita. As a part of samhita, an Online Programming...
1
by: Your Friend | last post by:
Hello All, I'm having issues capturing the output from a program while using threading. Program runs ok when I run without threading. Here's my Python code and the Java class that is called by...
21
by: Illumineo | last post by:
My application uses multiple-threads and is a kind of AI simulation or ALife. This works fine but I was wondering if and how one can make use of hyper-threading in C#? Thanks for any hint,...
1
by: James T | last post by:
Hi I am considering spawning a background thread to perform a long running task in my asp.net application and I was hoping someone could shed some light on several issues for which I have not...
16
by: One Handed Man \( OHM - Terry Burns \) | last post by:
Sorry if this gets duplicated, but I posted it and cant see it for a long time so repost. . . I have an application which is writing to a graphics object, the main UI thread and a worker thread...
0
by: Colmeister | last post by:
I recently read Jason Clark's excellent article on Unhandled Exceptions (http://msdn.microsoft.com/msdnmag/issues/04/06/NET/default.aspx) and have attempted to incorporate the features he talks...
4
by: DBC User | last post by:
I have a background process which reads a table to see if there are any pending requests. If there are any, then it will start a worker thread (only 10 allowed at a time) and executes a method. In...
3
by: Richard MSL | last post by:
I have a C# application that works, with a main menu where the user can choose different options that run, and then return to the menu. I want to change it so that the user can starting running an...
5
by: George Maicovschi | last post by:
As multi-threading is not built in PHP I've been using a hack letting the Apache server handle the multi-threading issues, but I'm really curious of other approaches to this issue. If anyone has...
126
by: Dann Corbit | last post by:
Rather than create a new way of doing things: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html why not just pick up ACE into the existing standard:...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 3 Jan 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). For other local times, please check World Time Buddy In...
0
by: abbasky | last post by:
### Vandf component communication method one: data sharing ​ Vandf components can achieve data exchange through data sharing, state sharing, events, and other methods. Vandf's data exchange method...
2
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 7 Feb 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:30 (7.30PM). In this month's session, the creator of the excellent VBE...
0
by: fareedcanada | last post by:
Hello I am trying to split number on their count. suppose i have 121314151617 (12cnt) then number should be split like 12,13,14,15,16,17 and if 11314151617 (11cnt) then should be split like...
0
by: stefan129 | last post by:
Hey forum members, I'm exploring options for SSL certificates for multiple domains. Has anyone had experience with multi-domain SSL certificates? Any recommendations on reliable providers or specific...
0
by: MeoLessi9 | last post by:
I have VirtualBox installed on Windows 11 and now I would like to install Kali on a virtual machine. However, on the official website, I see two options: "Installer images" and "Virtual machines"....
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, youll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: Aftab Ahmad | last post by:
Hello Experts! I have written a code in MS Access for a cmd called "WhatsApp Message" to open WhatsApp using that very code but the problem is that it gives a popup message everytime I clicked on...
0
by: Aftab Ahmad | last post by:
So, I have written a code for a cmd called "Send WhatsApp Message" to open and send WhatsApp messaage. The code is given below. Dim IE As Object Set IE =...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.