Kenoyer130
Kenoyer130

Reputation: 7318

Windows Forms Threads are losing their culture

We have a .net 3.5 multi-threaded windows forms application. Is is launching 4-5 background workers/ async calls to retrieve data. About 1 in 10 times, one of the threads throws the following error. Sometimes the error is a null exception instead but the same exact call stack. We have tracked the issue down to the thread somehow losing its CultureInfo. Anyone else ran into this?

System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code.
   at System.Globalization.CultureTableRecord.GetCultureTableRecord(String name, Boolean useUserOverride)
   at System.Globalization.CultureTableRecord.GetCultureTableRecord(Int32 cultureId, Boolean useUserOverride)
   at System.Globalization.CultureInfo..ctor(Int32 culture, Boolean useUserOverride)
   at System.Globalization.CultureInfo.GetCultureByLCIDOrName(Int32 preferLCID, String fallbackToString)
   at System.Globalization.CultureInfo.InitUserDefaultUICulture()
   at System.Globalization.CultureInfo.get_UserDefaultUICulture()
   at System.Threading.Thread.get_CurrentUICulture()
   at System.Resources.ResourceManager.GetString(String name, CultureInfo culture)
   at System.Environment.ResourceHelper.GetResourceStringCode(Object userDataIn)
   at System.Environment.GetResourceFromDefault(String key)
   at System.Diagnostics.StackTrace.ToString(TraceFormat traceFormat)
   at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
   at System.IO.StreamWriter.Init(Stream stream, Encoding encoding, Int32 bufferSize)
   at System.IO.StreamWriter..ctor(Stream stream, Encoding encoding, Int32 bufferSize)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.GetWriterForMessage(SoapClientMessage message, Int32 bufferSize)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Serialize(SoapClientMessage message)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)

Upvotes: 3

Views: 890

Answers (4)

Tom Andraszek
Tom Andraszek

Reputation: 1870

I got this exception (once, out of a blue), also in a .NET 3.5 app:

System.Threading.SynchronizationLockException: Object synchronization method was called from an unsynchronized block of code.
   at System.Globalization.CultureTableRecord.GetCultureTableRecord(String name, Boolean useUserOverride)
   at System.Globalization.CultureTableRecord.GetCultureTableRecord(Int32 cultureId, Boolean useUserOverride)
   at System.Globalization.CultureInfo..ctor(Int32 culture, Boolean useUserOverride)
   at System.Globalization.CultureInfo.GetCultureByLCIDOrName(Int32 preferLCID, String fallbackToString)
   at System.Globalization.CultureInfo.InitUserDefaultCulture()
   at System.Globalization.CultureInfo.get_UserDefaultCulture()
   at System.Threading.Thread.get_CurrentCulture()
   at System.Globalization.DateTimeFormatInfo.get_CurrentInfo()
   at System.DateTime.ToString(String format)

This happened in a locked section, but the lock was not a value type.

Upvotes: 0

Kenoyer130
Kenoyer130

Reputation: 7318

I found that CultureInfo.ClearCachedData was being called on every web request :/ Removing that fixed the issue. There seems that Culture still needs some sort of lock since thread A calls ClearCachedData and thread B requests the data and it throws a null exception.

Upvotes: 1

Chris Shain
Chris Shain

Reputation: 51359

From just looking at the call stack, this appears to be a framework bug (of sorts). It seems that the StreamWriter constructor is performing a non-thread-safe operation (accessing GetCultureTableRecord) through a complex series of calls. My recommendation would be to serialize your calls to the StreamWriter constructor:

// Put this somewhere convenient
public static Object swConstructorLock = new Object();

then, when you create your StreamWriters:

// Lock this constructor because it does something that isnt thread-safe as per http://stackoverflow.com/questions/16113366/windows-forms-threads-are-losing-their-culture
StreamWriter myStreamWriter;
lock (swConstructorLock) {
    myStreamWriter = new StreamWriter(theStreamToWrite);
}

Upvotes: 1

illegal-immigrant
illegal-immigrant

Reputation: 8244

Try playing with default culture for entire domain using CultureInfo.DefaultThreadCurrentCulture and/or CultureInfo.DefaultThreadCurrentUICulture and see if that helps. All in all, you'll be able to ensure whether it's related to thread's culture

UPD: that specific exception may be thrown when using sync methods like lock, Monitor, etc on value types, calls to sync methods will box value, creating new one every time. I doubt it could be such serios bug in framework.

Can you check your synchronization code?

UPD2: ok, let's try to debug.

After that, there is a high chance for a workaround/solution for you problem

Upvotes: 1

Related Questions