views:

125

answers:

4

I might inherit a somewhat complex multithreaded application, which currently has several files with 2+k loc, lots of global variables accessed from everywhere and other practices that I would consider quite smelly.

Before I start adding new features with the current patterns, I'd like to try and see if I can make the basic architecture of the application better. Here's a short description :

  • App has in memory lists of data, listA, listB
  • App has local copy of the data (for offline functionality) dataFileA, dataFileB
  • App has threads tA1, tB1 which update dirty data from client to server
  • Threads tA2, tB2 update dirty data from server to client
  • Threads tA3, tB3 update dirty data from in memory lists to local files

I'm kinda trouble on what different patterns, strategies, programming practices etc I should look into in order to have the knowledge to make the best decisions on this.

Here's some goals I've invented for myself:

  1. Keep the app as stable as possible
  2. Make it easy for Generic Intern to add new features (big no-no to 50 lines of boilerplate code in each new EditRecordX.cs )
  3. Reduce complexity

Thanks for any keywords or other tips which could help me on this project.

A: 

Hey,

I think you should take a look at this: http://msdn.microsoft.com/en-us/concurrency/default.aspx

And this blog entry: http://blogs.msdn.com/pfxteam/

And this: http://msdn.microsoft.com/en-us/devlabs/ee794896.aspx

Hope it helps.

TimothyP
Thanks for the comment. I will check those out, but at the moment I'm stuck in 2.0 universe, so possible solutions that come in vs2010 and 4.0 are pretty much out of my reach.
Morri
+1  A: 

I'd suggest another goal would be to remove/reduce global state and keep information on the stack as often as possible to reduce the possibility of race conditions and weird threading issues.

Perhaps it might be worth seeing if you can incorporate tA2, tB2, tA3 and tB3 into the same threads to kill a few. If that isn't possible consider putting them behind a facade (a thread that concerns itself with moving data requests between the UI and the service that is talking to the server). This is so the "user facing" code only has to deal with one client as opposed to two. (I don't count the backup as a client as this sounds like a one-way process).

If the threads (UI and facade) wait for one another to finish their requests then this should prevent a "pull update" happening at the same time as a "push update".

Quibblesome
"remove/reduce global state and keep information on the stack as often as possible" could you clarify on this, I'm not sure what you mean by stack?
Morri
By stack I mean the arguments that are passed into the current method. This is what is on top of the stack. If you remove global state and instead find ways to pass the relevant information around as arguments (and possibly even deep copys to avoid an operation on a reference on thread A to change data that thread B is working with) you will drastically reduce the potential for threading issues. Have a read up on the concept of "purity" especially in regards to functional programming for the original concept.
Quibblesome
http://en.wikipedia.org/wiki/Pure_function is the premise of purity. The best thing about "pure" code is that there are no race conditions. The worst thing about "pure" code is that technically it can't do anything useful (technically Console.WriteLine is impure). But the concept is worth appreciating, especially when dealing with threading.
Quibblesome
+1  A: 

For making these kind of changes in general you will want to look at Martin Fowler's Refactoring: Improving the Design of Existing Code (much of which is on the refactoring website) and also Refactoring to Patterns. You also might find Working Effectively with Legacy Code useful in supporting safe changes. None of this is as much help specifically with multithreading, except in that simpler code is easier to handle in a multithreading environment.

Kathy Van Stone
+1  A: 

To Quibblesome's excellent suggestions, I might also add that using immutable objects is often an effective way to reduce the risk of threading problems. (Immutable objects, like strings in .NET and Java, cannot be modified once they are created.)

glaxaco