Sunday, March 29, 2009

An Interesting Side-Effect of Concurrency: Removing Items from a Collection While Enumerating

Copyright 2008-2009, Paul Jackson, all rights reserved

During my presentation on Parallel Programming in .Net 4.0 at the Orlando Code Camp yesterday, I was asked a question that I didn’t know the answer to and didn’t have time in the session to try out.  The question had to do with the new concurrent collections (System.Collections.Concurrent) available in .Net 4.0 and whether their concurrency also enabled us to change the collection while it was being enumerated.

We all know that this is something we can’t do:

   1: var dictionary = new Dictionary<int, DateTime>();
   2:  
   3: for (int i = 0; i < 10; i++)
   4: {
   5:     dictionary.Add(i, DateTime.Now);
   6: }
   7:  
   8: foreach (var item in dictionary)
   9: {
  10:     Console.WriteLine("Key: {0}", item.Key);
  11:     dictionary.Remove(item.Key);
  12: }
  13:  
  14: Console.WriteLine("Items remaining: {0}", dictionary.Count);
  15: Console.ReadLine();

At line 11, trying to remove an item from the collection we’re enumerating over results in an InvalidOperationException -- Collection was modified; enumeration operation may not execute.

But an interesting side-effect of the concurrent collections in .Net 4.0 appears to be that this is now possible – obviously because one thread needs to be able to enumerate a concurrent collection while others are adding-to/removing-from.  So changing the code to use ConcurrentDictionary:

   1: var dictionary = new ConcurrentDictionary<int, DateTime>();
   2:  
   3: for (int i = 0; i < 10; i++)
   4: {
   5:     dictionary.TryAdd(i, DateTime.Now);
   6: }
   7:  
   8: foreach (var item in dictionary)
   9: {
  10:     Console.WriteLine("Key: {0}", item.Key);
  11:     var temp = item.Value;
  12:     dictionary.TryRemove(item.Key, out temp);
  13: }
  14:  
  15: Console.WriteLine("Items remaining: {0}", dictionary.Count);
  16: Console.ReadLine();

Results in our being able to enumerate the dictionary and remove each item as we process it. 

image

But what if we want to remove one of the items that hasn’t been processed yet?  What if some value in the current item being processed results in our needing to remove a future item?

   1: var dictionary = new ConcurrentDictionary<int, DateTime>();
   2:  
   3: for (int i = 0; i < 10; i++)
   4: {
   5:     dictionary.TryAdd(i, DateTime.Now);
   6: }
   7:  
   8: foreach (var item in dictionary)
   9: {
  10:     Console.WriteLine("Key: {0}", item.Key);
  11:     if (item.Key == 4)
  12:     {
  13:         DateTime temp = DateTime.Now;
  14:         dictionary.TryRemove(8, out temp);
  15:     }
  16: }
  17:  
  18: Console.WriteLine("Items remaining: {0}", dictionary.Count);
  19: Console.ReadLine();

In this example, when we process the item with a key of 4, we want to remove key 8 from the collection – which also works:

image

And corollary of this is also true, that if we try to add to the collection while enumerating:

   1: foreach (var item in dictionary)
   2: {
   3:     Console.WriteLine("Key: {0}", item.Key);
   4:  
   5:     if (dictionary.Count < 20)
   6:     {
   7:         dictionary.TryAdd(dictionary.Count + 1, DateTime.Now);
   8:     }
   9: }

It works as well:

image

So a special “thank you” to the gentleman in my session yesterday who asked the question.  It looks like the answer’s “yes”.

kick it on DotNetKicks.com Shout it

Saturday, March 28, 2009

Parallel Programming Session at Orlando Code Camp

Copyright 2008-2009, Paul Jackson, all rights reserved

Another great day at a code camp, this time in my hometown of Orlando.

I arrived a little late, due to a night out with friends Friday, so was only able to attend a couple sessions myself before presenting my Parallel Programming in .Net 4.0 session – again scheduled for the last slot of the day.  I’m not sure if there’s a message there or not.

The Orlando .Net User Group did a really good job on this event.  Things were very well organized with a large number of attendees.  One little thing that impressed was lunch – they had a ticket system for lunch that made things run very smoothly.  I certainly appreciated the separate line for speakers. :)  And it was nice to find that lunch was sandwiches from Honey Baked Ham – a nice break from pizza.

As with the South Florida Code Camp, the audience was great.  There were a lot of really good questions again.  What’s interesting is that I give this presentation multiple times to different audiences, but get different questions each time – that keeps things new and interesting for me too, especially when I don’t know the answer.  I know I’ll get a couple blog posts out of the questions I didn’t have an immediate answer for and the couple I still don’t. 

I want to say thank you to the attendees for making me feel appreciated – and special thanks to those who stopped by the podium to offer feedback after the session, I really appreciate that.

Again, anyone with questions, please feel free to email me: pjackson@lovethedot.net

To follow up on one of the questions, I am available to Florida user groups to present this session and its follow-on, a deeper dive into TaskManager and Parallel.For.  Feel free to email me at pjackson@lovethedot.net to make arrangements.

I once again ran out of time before being able to demo the VS 2010 parallel debugging tools, so I think I’ll have to drop that from code camp events – at user groups I can include it, because running 1:15 or 1:20 is okay.

Slides and demos from today’s presentation can be downloaded here:

Friday, March 27, 2009

The Blogger Next Door

Copyright 2008-2009, Paul Jackson, all rights reserved

The Internet, or at least portions of it, is often described as a community. A big one, spanning the globe and with a lot of those neighbors we’re just a bit concerned about … but a community none-the-less.

One of the cornerstones of community is the concept of banding together to help a neighbor in need. Whether it’s dropping off a casserole so someone doesn’t have to cook in a time of tragedy or an old-fashioned barn-raising, the act of a community reaching out to help an individual is one of the greatest goods humanity has ever created.

Part of the concept’s power is that many people can help one with very little effort – when the load is distributed across an entire community, it’s almost nothing for the individual contributors in the group, but a huge, positive impact on the receiver.

What does this have to do with .Net and programming? Nothing, really, it’s not another metaphor like my online dating post, but in the .Net blogging community, the bloggers and readers are sort of like neighbors – and one of our neighbors has a neighbor who needs some help. (Okay, that’s a bit convoluted, but you’ll get the point in a second.)

Over on the Fear and Loathing blog, Bil Simser has a post today, titled The Girl Next Door, about a neighbor and friend of his that needs a bit of help. The gist of it is that their daughter, Natalie, has been treated for a brain tumor and a result of the treatment is some physical limitations – difficulty holding a pencil, for instance.

In order to help Natalie start getting back to a typical life and start schooling again, they’d like to get her a laptop with Dragon Naturally Speaking – something that would allow her to use the computer with the physical limitations her treatment has placed on her. The family’s faced with some pretty hefty medical costs ($2400 / month), so this is not something they can readily afford … but the community can.

A large number of neighbors in our .Net community can each give a little bit and make a big difference in a little girl’s life.

It doesn’t have to be much from each member of the community and, even in these tight economic times, it doesn’t have to be that big a sacrifice. I spent $2 on a Venti black coffee this morning … I can give up my coffee tomorrow or the next few days in order to help someone, especially the friend of someone whose blog I get value from.

So read Bil’s post and see if our community can help a neighbor.

Tuesday, March 24, 2009

spicIE: Writing IE 7 and IE 8 Plugins in Managed Code

Copyright 2008-2009, Paul Jackson, all rights reserved

spicIE, a recent addition to MSDN Code Gallery, wraps the COMplex aspects of IE plugin development, allowing you to write plugins in managed code – C#, VB.Net, etc.

SpiceLogoSmall“SpicIE is a framework which allows you easily to extend Internet Explorer 7/8 with your own plugins. SpicIE wraps/hides the IE COM extension interfaces and makes it easy to develop browser extensions in managed programming languages.”

In my opinion, this is something long overdue.  Though I really haven’t had a need to write a browser plugin for anything, my perception – based on the availability of plugins and anecdotal evidence – is that it’s far easier to do in, say, Firefox or most other browsers than it is in Internet Explorer.  That being the case, when I saw spicIE today, I decided to download it and see just how much would be involved in writing my first plugin for IE.

First, I downloaded spicIE and installed it.  The install gives you a spicIE program group with two sample solutions, a help file and installation/deinstallation instructions:

image It also installs a Visual Studio template for spicIE projects:

imageThe template creates a project for you, including install/deinstall batch files, a strong-naming key and a Plugin.cs file:

image  Plugin.cs is the starting point for your plugin and inherits from SpicIE.Host.  The template apparently didn’t like my project name of LoveTheDot.PlugIn.IE and this resulted in some initial build errors:

imageThis is listed in the known issues, which I didn’t read before starting:

In case you're creating a new project from the SpicIE template, either in C# or VB.NET, you should be aware of a naming constraint. The project should not contain any dots or other special characters. Otherwise, there will be a problem with the defined class structure in the codefile of the plugin.

But these are quickly cleared up and the project then builds cleanly.

The plugin created by the template does have some basic functionality, it ties in to the OnDocumentComplete event and displays a “Hello World!” messagebox:

   1: public Plugin() : base()
   2: {
   3:     HostInstance = this;
   4:     this.OnDocumentComplete += Plugin_OnDocumentComplete;
   5: }
   6:  
   7: void Plugin_OnDocumentComplete(object pDisp, ref object url)
   8: {
   9:     MessageBox.Show("Hello World!");
  10: }

Building the project and executing the install batch file (which requires it be run as administrator), configures the plugin and now every page that loads within IE will say hello:

imageSo that’s a basic little plugin, but what do I want to do with it?  Well, being a playful and mischievous sort of fellow, I’ve decided to hijack MSDN. 

So with a little event subscription and a couple lines of code, my plugin can now redirect any arrival at a MSDN URI right back here to my little blog:

   1: public Plugin() : base()
   2: {
   3:     HostInstance = this;
   4:     this.OnNavigateComplete += Plugin_OnNavigateComplete;
   5: }
   6:  
   7: void Plugin_OnNavigateComplete(object pDisp, ref object URL)
   8: {
   9:     if (URL.ToString().StartsWith("http://msdn.microsoft.com"))
  10:         this.Navigate("http://www.lovethedot.net");
  11: }

Imagine the fun we could have just by changing those URIs to something more interesting and installing this plugin on coworkers’ machines …

Okay, so fun, but not very useful, what else can we do?  Really anything we might want to.  The spicIE API includes a wealth of possibilities, including access to the page’s Document model.  For instance, we could get a list of all the links on a page:

   1: public Plugin() : base()
   2: {
   3:     HostInstance = this;
   4:     this.OnDocumentComplete += Plugin_OnDocumentComplete;
   5: }
   6:  
   7: void Plugin_OnDocumentComplete(object pDisp, ref object url)
   8: {
   9:     foreach (var item in DocumentProperties.LinkCollection)
  10:     {
  11:         MessageBox.Show(item);
  12:     }
  13: }

(You’ll probably want to be careful where you run this little sample, or you’ll be clicking OK a lot.)

There’s a bit more involved if you want a user-interface (say a toolbar), but not much.

First create a user control and change it to inherit from SpicIE.Controls.Toolbar and there are two properties that must be overridden:

   1: public override string PluginGuid
   2: {
   3:     get
   4:     {
   5:         return "58AE4526-9474-4a80-A0CA-45BEFF07CEC9";
   6:     }
   7: }
   8:  
   9: public override string PluginProgID
  10: {
  11:     get
  12:     {
  13:         return "LoveTheDot.PlugIn.IE.Toolbar1";
  14:     }
  15: }

And some initialization to do in the constructor:

   1: public Toolbar1()
   2: {
   3:     InitializeComponent();
   4:     
   5:     this.ToolbarName = "Love the Dot Toolbar";
   6:     this.ToolbarTitle = "Love the Dot";
   7:  
   8:     this.ToolbarHelpText = "This is a very important toolbar";
   9:     this.ToolbarStyle = ToolbarEnum.ExplorerToolbar;
  10:  
  11:     // represents the startup size of the bar
  12:     this.Size = new Size(20, 20);
  13:     // represents the sizing steps
  14:     this.IntegralSize = new Size(0, 0);
  15:     // represents the minimum size
  16:     this.MinSize = new Size(20, 20);
  17:     // represents the maximum size
  18:     this.MaxSize = new Size(600, 600);
  19:  
  20:     // creates a new control collection and inserts the designer-generated controls
  21:     Control[] ctrls = new Control[Controls.Count];
  22:     Controls.CopyTo(ctrls, 0);
  23:  
  24:     // call internal method for implementing controls in the toolbar
  25:     BuildControls(ctrls);
  26: }

There’s a region in the Plugin.cs class for registering UI controls:

   1: #region Register your new browser UI elements here
   2:  
   3: internal static List<SpicIE.Controls.IControlBase> RunOnceCOMRegistration()
   4: {
   5:     Host.TraceSink.TraceEvent(TraceEventType.Information, 0,"RunOnceRegisterCOMControls");
   6:  
   7:     List<SpicIE.Controls.IControlBase> controls = new List<SpicIE.Controls.IControlBase>();
   8:     
   9:  
  10:  
  11:     return controls;
  12: }
  13:  
  14: #endregion

Just insert a line to add the new toolbar to the controls list:

   1: controls.Add(new Toolbar1());

And it becomes available in the browser:

image

In this case, I gave my toolbar a title and a single button, which I’ll code now just by handling the Clicked event like I would any other button:

   1: private void button1_Click(object sender, EventArgs e)
   2: {
   3:     Plugin.HostInstance.Navigate("http://www.lovethedot.net");
   4: }

The SpicIE.Host class, from which my Plugin descends, has a static method “HostInstance”, which gives access to the browser manipulation methods.  So now clicking on the toolbar button navigates the current browser tab to http://www.lovethedot.net.

By allowing us to write Internet Explorer 7/8 browser plugins with managed code, spicIE opens a plugin development to a whole new group of developers. 

kick it on DotNetKicks.com Shout it