views:

158

answers:

2

I'm writing an app for WM that handles incoming SMS events. I tried making it multi-threaded (using ThreadPool.QueueWorkItem) where the SmsMessage was passed along. However, I noticed that when I did that, the program would only handle the first sms event - afterwards, NO SMS were received by the device at all! But when the program exits, then all the missed SMSs arrived.

Based on that, I'd guess that the answer to my question is that SmsMessage objects are NOT thread-safe, even though there's not really an indication that that's the case.

So what if we want to try and thread an SmsMessage Object? I'll try that out tonight by making a copy of the SmsMessage (probably by using the constructor w/ item id), or I'll create an empty one and copy the fields manually.

DISCOVERY:

I narrowed down my problem. I was able to get everything to work in a background thread when I copied the SmsMessage into my own object, taking care not to reference any of the SmsMessage's objects. SMSs went flying through with no problem.

However, when I set up an MessageIntercepter to launch an application, and within that application instance, use a background thread to send an SMS, the application would work fine, but after it exits my code it crashes and displays the "There was an error in yourapp.exe" and asks me if you want to send the crash data to MS. I could never figure out what that error was, but I found out that if I sent the SMS from the same thread that launched the application, everything worked fine.

So, threading when the app is open = fine, as long as you don't pass/use the SmsMessage Threading when the app is externally launched = fine, as long as you don't send an SmsMessage in another thread.

A: 

Without seeing more code, it's hard to guess what's happening. I strongly suspect that it was a problem with your threading code rather than with SmsMessage.

If you could explain the architecture of your application, that would help a lot. I wouldn't be surprised to find you'd got a deadlock somewhere which was blocking everything.

Jon Skeet
I don't think it's a deadlock issue, I wrote a simple app to test the behavior and it still happens. I stepped through the background thread and it executes fully, and doesn't throw exceptions. But when it's done I don't receive any more SmsMessage events until the application terminates.
ZaijiaN
Please post your simple app then - that would make it a *lot* easier to see what's going on.
Jon Skeet
+2  A: 

According to the MSDN Library (Microsoft.WindowsMobile.PocketOutlook.SmsMessage):

Any public static (Shared in Visual Basic) members of this type are thread-safe. Any instance members are not guaranteed to be thread-safe.

So the answer to your question is: it is not thread-safe.

EDIT: I'm glad you managed to get this thing working. I'm pretty sure it's some race condition or unmanaged resource handling issue deep down in the PocketOutlook library.

Personally, I think you should keep all your messaging-related code in a single thread, from the point the MessageInterceptor created until the point it gets disposed and only pass objects that are written by you so you know that they don't have dodgy unmanaged dependecies (that's kind of what you did I think) - this should be enough to avoid these problems.

What's the point of having 2 SMS interceptor threads anyway? It's not like a phone could receive 2 text messages the same time.

DrJokepu
+1 Agreed. Unless you can view the source, you should never make *any* assumptions about thread safety.
ctacke
ctacke: Or, obviously, if it is documented that it is thread-safe.
DrJokepu
So it's not thread-safe, but if I created an SmsMessage with the ItemId constructor, would THAT object be thread-safe... hMMmmm...
ZaijiaN
You will have to create a separate SmsMessage instance for each thread or if you want to have a single one only, you will have to lock it.
DrJokepu
Sounds good DrJokepu, i'll try that and post my results.
ZaijiaN
Most things which say they're not thread-safe just mean you shouldn't access them from two threads at the same time. You should be fine to effectively pass it from one thread to another to deal with.
Jon Skeet
I think the problem i'm running into may be because the WM OS is doing something (disposing maybe?) with the SmsMessage after it fired all the events.
ZaijiaN
I think the source problem is somewhere at the message interception part, not in the SmsMessage class. Maybe you declared your MessageInterception in the function scope insted of class scope so it gets garbage collected quickly? The MSDN documentation says that this is a typical problem.
DrJokepu
"When defining an instance of MessageInterceptor that is going to handle the MessageReceived event, make sure that the instance is defined globally in the class where the event will be handled. If it is defined in a method, it will be up for garbage collection after it goes out of scope." - MSDN
DrJokepu
The message interceptor delegate is a member variable in a long-lived class, so it shouldn't be getting garbage-collected
ZaijiaN
@chublogga: The documentation says otherwise. It is always a good idea to follow the documentation. http://msdn.microsoft.com/en-us/library/microsoft.windowsmobile.pocketoutlook.messageinterception.messageinterceptor.aspx
DrJokepu
@DrJokepu: I meant that I am defining a MessageInterceptor as an instance variable of a class that lives for the entire lifetime of my application. IE there is always a reference to it while I am using it, so it shouldn't be getting GC'd, right?
ZaijiaN
Also, I'm not using 2 MessageInterceptor threads - I am spinning off a ThreadPool thread from the originating MessageInterceptor delegate, and was having problems whenever I passed the SmsMessage to the ThreadPool thread. So I made a similar class called SmsMessageCopy and copied the properties.
ZaijiaN