Anyone from Microsoft confirm this bug or explain this as feature

  • Thread starter Thread starter Aamir Mahmood
  • Start date Start date
A

Aamir Mahmood

I have posted this issue earlier on
microsoft.public.dotnet.languages.csharp, but nobody replied to that.

Consider following code:

--------------------------------------------------------------------------------

private void button1_Click(object sender, EventArgs e) {
using (System.Transactions.TransactionScope tx = new TransactionScope())
{
System.Transactions.Transaction.Current.TransactionCompleted += new
TransactionCompletedEventHandler(Current_TransactionCompleted);

System.Console.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode());
// prints 4, could be different on your machine
throw new Exception();

tx.Commit();
}
}

private void Current_TransactionCompleted(object sender,
TransactionEventArgs e) {
System.Console.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode());
// prints 6, could be different on your machine
}

--------------------------------------------------------------------------------

The problem is the output, first it outputs 4, and it ouputs 6 (it can be a
different output on your machine).

I have various fields with [ThreadStatic] attribute. Since the
TransactionCompleted is coming on a different thread, it is making all those
[ThreadStatic] fields useless.
This is driving me crazy.

The event MUST be fired on the same thread that created TransactionScope and
subscribed this event.
But the Microsoft implemented in a way, that the initial thread is stopped
and a different thread is used to fire the event (WHY???). After the event
handler function finishes, application continues with the original thread.
WHY EVENT IS FIRED ON A DIFFERENT THREAD? I have [ThreadStatic] members
which I cannot use.
I have cleanup routines which were tied to that specific transactions
created for that specific thread.

Since this is not explained in any documentation, I think it is a bug.

Thanks.

AM.
 
The problem is the output, first it outputs 4, and it ouputs 6 (it can be a
different output on your machine).

I have various fields with [ThreadStatic] attribute. Since the
TransactionCompleted is coming on a different thread, it is making all those
[ThreadStatic] fields useless.

Then you've got a design issue - it doesn't mean it's a bug.
This is driving me crazy.

The event MUST be fired on the same thread that created TransactionScope and
subscribed this event.

Well, it must for your code to work. I can't immediately see anything
in the documentation suggesting that that should happen though.
But the Microsoft implemented in a way, that the initial thread is stopped
and a different thread is used to fire the event (WHY???). After the event
handler function finishes, application continues with the original thread.
WHY EVENT IS FIRED ON A DIFFERENT THREAD? I have [ThreadStatic] members
which I cannot use.
I have cleanup routines which were tied to that specific transactions
created for that specific thread.

Since this is not explained in any documentation, I think it is a bug.

Where is the guarantee to that it *will* occur in the same thread? If
there's no guarantee, you're relying on unspecified behaviour, which
you assumed would be the behaviour you wanted.

What would you expect to happen if you'd called BeginCommit from a
thread which wasn't running a message pump? How would you expect it to
marshall back to that thread?
 
I was not going to add anything here, as Jon has already provided a long
answer, but it started nagging on me, so I apologize, in advance.

First, let's understand bug and design flaw. Suppose I create a library that
creates a binary array out of a string. As I am working with English only, I
design this to return a single byte per character in the string. You,
working in another language, find that it is not giving you enough fidelity
to reproduce your string on the other end. So you call and say I have a bug.

My library does what I said it would do, so it is not a bug. If my library
turned the word fudge into the binary representation of turds, it would be a
bug, as it is not working as I stated it would work.

It could, however, be a design flaw, as it only works with ASCII values. The
question of whether or not it is a design flaw depends on stated intent. For
example, "creates a binary representation of an ASCII string" would not
indicate a design flaw, while "creates a binary representation of any
string" would.

-----------

Next, I see the statement
I have cleanup routines which were tied to that specific transactions
created for that specific thread

So, you have a cleanup dependent not ONLY on the transaction, but on the
particular thread. This means your cleanup is actually work that is part of
the transaction, as it has a very tightly coupled dependency on more than
the work being done, but the actual manner in which it is completed. In
other words, the TransactionScope is not really what you are concerned with,
but the thread created to complete the TransactionScope.

If you ask me, it is a design flaw. It might be Microsoft's design flaw, as
they have not included a way to create a transaction for a transaction and
its cleanup. But, as you have the dependency, I would also argue that you
have a design flaw in your own code, as the TransactionScope is acting
exactly as published.

Let's, however, focus on it being a bug that Microsoft needs to fix. If so,
it will likely take weeks, at minimum, before we see a patch of any sort,
and months before a fully regression tested patch. Can you wait this long
before you fix the problem? If yes, then get on connect and log the bug. If
not, I would find a way to eliminate the thread dependency in your code. At
this point, working code is probably better than being right.

--
Gregory A. Beamer
MVP, MCP: +I, SE, SD, DBA

Subscribe to my blog
http://gregorybeamer.spaces.live.com/lists/feed.rss

or just read it:
http://gregorybeamer.spaces.live.com/

*************************************************
| Think outside the box!
|
*************************************************
Aamir Mahmood said:
I have posted this issue earlier on
microsoft.public.dotnet.languages.csharp, but nobody replied to that.

Consider following code:

--------------------------------------------------------------------------------

private void button1_Click(object sender, EventArgs e) {
using (System.Transactions.TransactionScope tx = new
TransactionScope()) {
System.Transactions.Transaction.Current.TransactionCompleted += new
TransactionCompletedEventHandler(Current_TransactionCompleted);


System.Console.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode());
// prints 4, could be different on your machine
throw new Exception();

tx.Commit();
}
}

private void Current_TransactionCompleted(object sender,
TransactionEventArgs e) {

System.Console.WriteLine(System.Threading.Thread.CurrentThread.GetHashCode());
// prints 6, could be different on your machine
}

--------------------------------------------------------------------------------

The problem is the output, first it outputs 4, and it ouputs 6 (it can be
a different output on your machine).

I have various fields with [ThreadStatic] attribute. Since the
TransactionCompleted is coming on a different thread, it is making all
those [ThreadStatic] fields useless.
This is driving me crazy.

The event MUST be fired on the same thread that created TransactionScope
and subscribed this event.
But the Microsoft implemented in a way, that the initial thread is stopped
and a different thread is used to fire the event (WHY???). After the
event handler function finishes, application continues with the original
thread. WHY EVENT IS FIRED ON A DIFFERENT THREAD? I have [ThreadStatic]
members which I cannot use.
I have cleanup routines which were tied to that specific transactions
created for that specific thread.

Since this is not explained in any documentation, I think it is a bug.

Thanks.

AM.
 
The TransactionCompleted event is raised on the thread on which the
transaction is running. This is very common for events, if thread affinity
isn't documented then you can't assume it will occur on any particular
thread. It's your applications requirement that the event handle execute on
a given thread. It's your application's responsibility to marshal the call
to another thread, if needed.

Given that a Form cannot have it's form data accessed by any other thread,
why are you using the ThreadStatic attribute on fields on a Form class anyway?
 
Peter said:
The TransactionCompleted event is raised on the thread on which the
transaction is running. This is very common for events, if thread
affinity isn't documented then you can't assume it will occur on any
particular thread. It's your applications requirement that the event
handle execute on a given thread. It's your application's
responsibility to marshal the call to another thread, if needed.

Given that a Form cannot have it's form data accessed by any other
thread, why are you using the ThreadStatic attribute on fields on a
Form class anyway?

The data associated with a Form can be accessed from any thread, what makes
you think otherwise? Only operations that require sending windows messages
to the HWND have thread affinity.
 
"Form data" as in controls. It's actually a combination of windows messages
and the fact that the main (GUI) thread must be STA that cause cross-thread
control access exceptions.

But, the documentation for Control.InvokeRequired details it quite well:
"Controls in Windows Forms are bound to a specific thread and are not thread
safe. Therefore, if you are calling a control's method from a different
thread, you must use one of the control's invoke methods to marshal the call
to the proper thread."

There's certain cases where you don't have to Invoke; but it's difficult to
track down which will and which won't case an exception and usually just
easier to marshal all access to the form's thread.

--
Browse http://connect.microsoft.com/VisualStudio/feedback/ and vote.
http://www.peterRitchie.com/blog/
Microsoft MVP, Visual Developer - Visual C#
 
Peter Duniho said:
It seems to me that "form data" is not naturally inferred to mean simply
"controls". My guess is that that's the point of disagreement between you
and Ben. I think he rightly took issue with the over-general statement
about what requires the use of Invoke().

Quite possibly.

It's true that most of the properties and methods in the Form class itself
must be called from the thread that owns that instance of the Form.

Yes, and that's why I asked about the OP's use of ThreadStatic. If many (or
even just some) of the form/control's methods/properties need to be marshaled
to a specific thread, having thread-specific fields seems like a really bad
idea.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top