Amazon.com Widgets All posts tagged '.net'

WilliaBlog.Net

I dream in code

About the author

Robert Williams is an internet application developer for the Salem Web Network.
E-mail me Send mail
Code Project Associate Logo
Go Daddy Deal of the Week: 30% off your order at GoDaddy.com! Offer expires 11/6/12

Recent comments

Archive

Authors

Tags

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.


Working with Metafile Images in .Net

What is a Metafile Image?

The Windows Metafile (WMF) is a graphics file format on Microsoft Windows systems, originally designed in the 1990s.

Internally, a metafile is an array of variable-length structures called metafile records. The first records in the metafile specify general information such as the resolution of the device on which the picture was created, the dimensions of the picture, and so on. The remaining records, which constitute the bulk of any metafile, correspond to the graphics device interface (GDI) functions required to draw the picture. These records are stored in the metafile after a special metafile device context is created. This metafile device context is then used for all drawing operations required to create the picture. When the system processes a GDI function associated with a metafile DC, it converts the function into the appropriate data and stores this data in a record appended to the metafile.

After a picture is complete and the last record is stored in the metafile, you can pass the metafile to another application by:

  • Using the clipboard
  • Embedding it within another file
  • Storing it on disk
  • Playing it repeatedly

A metafile is played when its records are converted to device commands and processed by the appropriate device.

There are two types of metafiles:

I had worked with Metafiles in Visual Basic 6 many years ago, when I worked for Taltech.com, a company that strives to produce the highest quality barcode images that Windows can create. As I remember it, this involved making lots of Windows API calls, and something called "Hi Metric Map Mode" (MM_HIMETRC). "Basically, the mapping mode system enables you to equate an abstract, logical drawing surface with a concrete and constrained display surface.  This is good in principle but GDI had a major drawback inasmuch as the logical drawing area coordinates were based upon signed integers.  This meant that creating drawing systems based upon some real-world measurement system such as inches or millimeters required you to use a number of integer values to represent a single unit of measure for example, in the case of MM_LOMETRC mapping there are ten integer values to each linear millimeter and in the case of MM_LOENGLISH there are 100 integer values to each linear inch." - Bob Powell. Bob has written a great article: Comparing GDI mapping modes with GDI+ transforms for anyone wanting to learn more about this.

Bob goes on to say that "Given the fact that matrix transformations have been recognized as the only sensible method to manipulate graphics for many years, GDI mapping modes were a very limited alternative and always a bit of a kludge", and he's probably right. To be honest, all that matrix stuff went way over my head. Luckily, today, the simplicity of matrix transformations is built into GDI+, and most of those API calls have been integrated into the System.Drawing Namespaces of the .Net Framework. Having already found a way to draw a barcode as a bitmap using the .Net Framework, I wanted to see how easy it would be to create a barcode as a metafile, since bitmaps are a lossy format, and barcodes need to be as high quality as possible to ensure that the scanners read them correctly.

You might think that creating a metafile would be as easy as using the Save() Method of System.Drawing.Image and giving the file a .wmf or .emf extension, but sadly this is not the case. If you do that, what you actually get, is a Portable Network Graphics (PNG) file, with a .wmf or .emf extension. Even if you use the ImageFormat overload, and pass in the filename and ImageFormat.Emf or ImageFormat.Wmf, you still end up with a PNG. It doesn't matter whether you create a Bitmap and call Save() or you go to the trouble of creating an in memory Metafile (more on that later) and then call Save(), you will never get a true Metafile. If you visit the MSDN documentation on the Metafile Class, you can see under 'Remarks' it casually states:

When you use the Save method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, the resulting file is saved as a Portable Network Graphics (PNG) file instead. This behavior occurs because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.

This is confirmed in the documentation for the System.Drawing.Image.Save Method:

If no encoder exists for the file format of the image, the Portable Network Graphics (PNG) encoder is used. When you use the Save() method to save a graphic image as a Windows Metafile Format (WMF) or Enhanced Metafile Format (EMF) file, the resulting file is saved as a Portable Network Graphics (PNG) file. This behavior occurs because the GDI+ component of the .NET Framework does not have an encoder that you can use to save files as .wmf or .emf files.

Saving the image to the same file it was constructed from is not allowed and throws an exception.

In order to save your in memory metafile as a true metafile, you must make some old fashioned API calls, and I will show you how to do this in due course, but first you need to know how to create an in memory Metafile. Let's assume that, like me, you already have some code that generates a bitmap image which looks just the way you want it. Here is some sample code distilled from a nice BarCode Library project written by Brad Barnhill

        static void Main(string[] args)

        {

            int width = 300;

            int height = 100;

 

            Bitmap b = new Bitmap(width, height);

            int pos = 0;

            string encodedValue =

                "1001011011010101001101101011011001010101101001011010101001101101010100110110101010011011010110110010101011010011010101011001101010101100101011011010010101101011001101010100101101101";

            int barWidth = width / encodedValue.Length;

            int shiftAdjustment = (width % encodedValue.Length) / 2;

            int barWidthModifier = 1;

 

            using (Graphics g = Graphics.FromImage(b))

            {

                // clears the image and colors the entire background

                g.Clear(Color.White);

 

                // lines are barWidth wide so draw the appropriate color line vertically

                using (Pen pen = new Pen(Color.Black, (float)barWidth / barWidthModifier))

                {

                    while (pos < encodedValue.Length)

                    {

                        if (encodedValue[pos] == '1')

                        {

                            g.DrawLine(

                                pen,

                                new Point(pos * barWidth + shiftAdjustment + 1, 0),

                                new Point(pos * barWidth + shiftAdjustment + 1, height));

                        }

 

                        pos++;

                    } // while

                } // using

            } // using

 

            b.Save(@"d:\temp\test.png", ImageFormat.Png);

        }

As you can see, this code creates a new Bitmap image, creates a Graphics object from it, draws on it using the Pen class then saves it as a .png. The resulting image looks like this:

So far so good. As we have already established, simply rewriting the last line as

b.Save(@"d:\temp\test.emf", ImageFormat.Emf);

is not enough to convert this image to a metafile. Sadly, substituting the word "Metafile" for "Bitmap" is not all it takes to create an in memory metafile. Instead, you will need to have a device context handle and a stream handy. If you are working on a Windows Forms application you can create a Graphics object easily by simply typing Graphics g = this.CreateGraphics(); but if you are writing a class library or a console application you have to be a bit more creative and use an internal method (FromHwndInternal) to create the Graphics object out of nothing:

            Graphics offScreenBufferGraphics;

            Metafile m;

            using (MemoryStream stream = new MemoryStream())

            {

                using (offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))

                {

                    IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();

                    m = new Metafile(

                        stream,

                        deviceContextHandle,

                        EmfType.EmfPlusOnly);

                    offScreenBufferGraphics.ReleaseHdc();

                }

            }

OK, so now your code looks like this:

        static void Main(string[] args)

        {

            int width = 300;

            int height = 100;

 

            Graphics offScreenBufferGraphics;

            Metafile m;

            using (MemoryStream stream = new MemoryStream())

            {

                using (offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))

                {

                    IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();

                    m = new Metafile(

                        stream,

                        deviceContextHandle,

                        EmfType.EmfPlusOnly);

                    offScreenBufferGraphics.ReleaseHdc();

                }

            }

 

            int pos = 0;

            string encodedValue =

                "1001011011010101001101101011011001010101101001011010101001101101010100110110101010011011010110110010101011010011010101011001101010101100101011011010010101101011001101010100101101101";

            int barWidth = width / encodedValue.Length;

            int shiftAdjustment = (width % encodedValue.Length) / 2;

            int barWidthModifier = 1;

 

            using (Graphics g = Graphics.FromImage(m))

            {

                // clears the image and colors the entire background

                g.Clear(Color.White);

 

                // lines are barWidth wide so draw the appropriate color line vertically

                using (Pen pen = new Pen(Color.Black, (float)barWidth / barWidthModifier))

                {

                    while (pos < encodedValue.Length)

                    {

                        if (encodedValue[pos] == '1')

                        {

                            g.DrawLine(

                                pen,

                                new Point(pos * barWidth + shiftAdjustment + 1, 0),

                                new Point(pos * barWidth + shiftAdjustment + 1, height));

                        }

 

                        pos++;

                    } // while

                } // using

            } // using

 

            m.Save(@"d:\temp\test2.png", ImageFormat.Png);

         }

But wait, what happened to my barcode? It's all off center, yet the code used to draw it hasn't changed:

Luckily this is easy to fix. We need to use a different overload when creating the metafile, so that we can specify a width and height, and a unit of measure:

            Graphics offScreenBufferGraphics;

            Metafile m;

            using (MemoryStream stream = new MemoryStream())

            {

                using (offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))

                {

                    IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();

                    m = new Metafile(

                        stream,

                        deviceContextHandle,

                        new RectangleF(0, 0, width, height),

                        MetafileFrameUnit.Pixel,

                        EmfType.EmfPlusOnly);

                    offScreenBufferGraphics.ReleaseHdc();

                }

            }

 

Now it looks the same when saved as a .png, but it may still look all wrong (and more importantly be completely unreadable by a barcode scanner) if printed and the resolution of the printer does not match that of your desktop when you created the metafile. Furthermore, if I save this as a real EMF file and email it to you, when you view it you may see a different rendering, because the desktop I created it on has a resolution of 1920x1080, but if your desktop has a higher or lower resolution it will affect how it is displayed. Remember a metafile is a stored set of instructions on how to render the image and by default it will use the stored resolution for reference. To correct this, we have to add some additional code to the Graphics object to ensure this doesn't happen (thanks go to Nicholas Piasecki and his blog entry for pointing this out):

 

                MetafileHeader metafileHeader = m.GetMetafileHeader();

                g.ScaleTransform(metafileHeader.DpiX / g.DpiX, metafileHeader.DpiY / g.DpiY);

                g.PageUnit = GraphicsUnit.Pixel;

                g.SetClip(new RectangleF(0, 0, width, height));

So how can we save it as a real Metafile anyway?

Well, first we need to declare some old fashioned Win API calls:

        [DllImport("gdi32.dll")]

        static extern IntPtr CopyEnhMetaFile(  // Copy EMF to file

            IntPtr hemfSrc,   // Handle to EMF

            String lpszFile // File

        );

 

        [DllImport("gdi32.dll")]

        static extern int DeleteEnhMetaFile(  // Delete EMF

            IntPtr hemf // Handle to EMF

        );

Then we can replace the m.Save(...); line with this:

            // Get a handle to the metafile

            IntPtr iptrMetafileHandle = m.GetHenhmetafile();

 

            // Export metafile to an image file

            CopyEnhMetaFile(iptrMetafileHandle, @"d:\temp\test2.emf");

 

            // Delete the metafile from memory

            DeleteEnhMetaFile(iptrMetafileHandle);

and finally we have a true metafile to share. Why Microsoft failed to encapsulate this functionality within the framework as an image encoder is a mystery. Windows Metafiles, and Enhanced Metafiles are after all their own creation. So our final version of the code looks like this:

        static void Main(string[] args)

        {

            int width = 300;

            int height = 100;

 

            Graphics offScreenBufferGraphics;

            Metafile m;

            using (MemoryStream stream = new MemoryStream())

            {

                using (offScreenBufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))

                {

                    IntPtr deviceContextHandle = offScreenBufferGraphics.GetHdc();

                    m = new Metafile(

                        stream,

                        deviceContextHandle,

                        new RectangleF(0, 0, width, height),

                        MetafileFrameUnit.Pixel,

                        EmfType.EmfPlusOnly);

                    offScreenBufferGraphics.ReleaseHdc();

                }

            }

 

            int pos = 0;

            string encodedValue =

                "1001011011010101001101101011011001010101101001011010101001101101010100110110101010011011010110110010101011010011010101011001101010101100101011011010010101101011001101010100101101101";

            int barWidth = width / encodedValue.Length;

            int shiftAdjustment = (width % encodedValue.Length) / 2;

            int barWidthModifier = 1;

 

            using (Graphics g = Graphics.FromImage(m))

            {

                // Set everything to high quality

                g.SmoothingMode = SmoothingMode.HighQuality;

                g.InterpolationMode = InterpolationMode.HighQualityBicubic;

                g.PixelOffsetMode = PixelOffsetMode.HighQuality;

                g.CompositingQuality = CompositingQuality.HighQuality;

 

                MetafileHeader metafileHeader = m.GetMetafileHeader();

                g.ScaleTransform(

                    metafileHeader.DpiX / g.DpiX,

                    metafileHeader.DpiY / g.DpiY);

 

                g.PageUnit = GraphicsUnit.Pixel;

                g.SetClip(new RectangleF(0, 0, width, height));

 

                // clears the image and colors the entire background

                g.Clear(Color.White);

 

                // lines are barWidth wide so draw the appropriate color line vertically

                using (Pen pen = new Pen(Color.Black, (float)barWidth / barWidthModifier))

                {

                    while (pos < encodedValue.Length)

                    {

                        if (encodedValue[pos] == '1')

                        {

                            g.DrawLine(

                                pen,

                                new Point(pos * barWidth + shiftAdjustment + 1, 0),

                                new Point(pos * barWidth + shiftAdjustment + 1, height));

                        }

 

                        pos++;

                    } // while

                } // using

            } // using

 

            // Get a handle to the metafile

            IntPtr iptrMetafileHandle = m.GetHenhmetafile();

 

            // Export metafile to an image file

            CopyEnhMetaFile(iptrMetafileHandle, @"d:\temp\test2.emf");

 

            // Delete the metafile from memory

            DeleteEnhMetaFile(iptrMetafileHandle);

        }

There is one more Metafile Gotcha I'd like to share. As part of my original Bitmap generating code, I had a boolean option to generate a label, that is the human readable text that appears beneath the barcode. If this option was selected, before returning the bitmap object I would pass it to another method that looked something like this:

        static Image DrawLabel(Image img, int width, int height)

        {

            Font font = new Font("Microsoft Sans Serif", 10, FontStyle.Bold); ;

 

            using (Graphics g = Graphics.FromImage(img))

            {

                g.DrawImage(img, 0, 0);

                g.SmoothingMode = SmoothingMode.HighQuality;

                g.InterpolationMode = InterpolationMode.HighQualityBicubic;

                g.PixelOffsetMode = PixelOffsetMode.HighQuality;

                g.CompositingQuality = CompositingQuality.HighQuality;

 

                StringFormat f = new StringFormat();

                f.Alignment = StringAlignment.Center;

                f.LineAlignment = StringAlignment.Near;

                int LabelX = width / 2;

                int LabelY = height - font.Height;

 

                //color a background color box at the bottom of the barcode to hold the string of data

                g.FillRectangle(new SolidBrush(Color.White), new RectangleF((float)0, (float)LabelY, (float)width, (float)font.Height));

 

                //draw datastring under the barcode image

                g.DrawString("038000356216", font, new SolidBrush(Color.Black), new RectangleF((float)0, (float)LabelY, (float)width, (float)font.Height), f);

 

                g.Save();

            }

 

            return img;

        }

When passing the bitmap, this works great, but when passing the metafile, the line using (Graphics g = Graphics.FromImage(img)) would throw a System.OutOfMemoryException every time. As a workaround, I copied the label generating code into the main method that creates the barcode. Another option might be to create a new metafile (not by calling m.Clone() - I tried that and still got the out of memory exception), send that to the DrawLabel() method, then when it comes back, create a third Metafile, and call g.DrawImage() twice (once for each metafile that isn't still blank) and return this new composited image. I think that will work, but I also think it would use a lot more resources and be grossly inefficient, so I think copying the label code into both the DrawBitmap() and DrawMetafile() methods, is a better solution.


Categories: C# | CodeProject | Windows
Posted by Williarob on Monday, April 04, 2011 6:51 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Checking for a Running Instance

Sometimes you may not want a user to launch multiple instances of your program, or you may have a processor or I/O intensive scheduled task that runs every few minutes and you want to make sure that if it is started again before the last instance has finished it simply exits immediately. One way to check to see if your program is already running is to look at the list of running processes:

 

namespace RunningInstance

{

    using System;

    using System.Diagnostics;

    using System.Reflection;

 

    class Program

    {

        static void Main(string[] args)

        {

            if (RunningInstance())

            {

                Console.WriteLine("Another instance of this process was already running, exiting...");

                return;

            }

 

            // ...

        }

 

        static bool RunningInstance()

        {

            Process current = Process.GetCurrentProcess();

            Process[] processes = Process.GetProcessesByName(current.ProcessName);

 

            // Loop through the running processes in with the same name

            foreach (Process p in processes)

            {

                // Ignore the current process

                if (p.Id != current.Id)

                {

                    // Make sure that the process is running from the exe file.

                    if (Assembly.GetExecutingAssembly().Location.Replace("/", @"\") == current.MainModule.FileName)

                    {

                        return true;

                    }

                }

            }

 

            return false;

        }

    }

}

 

However, suppose you have a multi function console application that accepts a dozen different command line arguments to perform different jobs, all of which run as separate scheduled tasks at overlapping intervals. If this is the case, then checking the list of running processes may well find your executable already running, but have no idea which command line argument was used to start it. I tried adding:

 

Console.WriteLine("Instance started with args: '{0}'", p.StartInfo.Arguments);

above the "return true" statement in RunningInstance() but it will not print the command line args used to start it. Lets suppose we add 2 classes to our project. Task1 and Task2. For the sake of simplicity, they both look something like this:

namespace RunningInstance

{

    using System;

    using System.Threading;

 

    public class Task1

    { 

        public void Start()

        {

            Console.WriteLine("Starting Task 1");

        }

    }

}

 

Task 2 is exactly the same, except it prints "Starting Task 2". If we keep our RunningInstance check in place Main() now looks like this:

 

        static void Main(string[] args)

        {

            if (RunningInstance())

            {

                Console.WriteLine("An instance of this application is already running. Exiting.");

                Console.ReadLine();

                return;

            }

 

            if(args.Length < 1)

            {

                Console.WriteLine("Unrecognized Command.");

                return;

            }

 

            switch (args[0])

            {

                case "-task1":

                    var t1 = new Task1();

                    t1.Start();

                    break;

                case "-task2":

                    var t2 = new Task2();

                    t2.Start();

                    break;

                default:

                    Console.WriteLine("Unrecognized Command.");

                    break;

            }

        }

Task 2 will not run, if task 1 is still running, and vice versa. However, suppose the two tasks are completely unrelated. The first is only a minor chore, that simply counts the number of items marked as "queued" in a database table and sends out an email if the number is too high, while task 2 is much lengthier process that FTPs files. We may need both of these tasks to run as scheduled, but not want multiple instances of either task to run at the same time. How can we achive this? We use a Mutex. Mutex is an abbreviation of "Mutual exclusion" and is traditionally used in multi threaded applications to avoid the simultaneous use of a common resource, such as a global variable. After adding a mutex to each task, our final code looks like this:


        static void Main(string[] args)

        { 

            if(args.Length < 1)

            {

                Console.WriteLine("Unrecognized Command.");

                return;

            }

 

            switch (args[0])

            {

                case "-task1":

                    var t1 = new Task1();

                    t1.Start();

                    break;

                case "-task2":

                    var t2 = new Task2();

                    t2.Start();

                    break;

                default:

                    Console.WriteLine("Unrecognized Command.");

                    break;

            }

        }

 

 

namespace RunningInstance

{

    using System;

    using System.Threading;

 

    public class Task1

    {

        /// <summary>Gets the mutex that prevents multiple instances of this code running at once.</summary>

        private static Mutex mutex1;

 

        public void Start()

        {

            bool createdNew;

            mutex1 = new Mutex(true, "RunningInstance.Task1", out createdNew);

            if (!createdNew)

            {

                // Instance already running; exit.

                Console.WriteLine("Exiting: Instance already running");

                return;

            }

 

            Console.WriteLine("Starting Task 1");

        }

    }

}

 

 

namespace RunningInstance

{

    using System;

    using System.Threading;

 

    public class Task2

    {

        /// <summary>Gets the mutex that prevents multiple instances of this code running at once.</summary>

        private static Mutex mutex1;

 

        public void Start()

        {

            bool createdNew;

            mutex1 = new Mutex(true, "RunningInstance.Task2", out createdNew);

            if (!createdNew)

            {

                // Instance already running; exit.

                Console.WriteLine("Exiting: Instance already running");

                return;

            }

            Console.WriteLine("Starting Task 2");

        }

    }

}

 

Each Task has its own Mutex, uniquely named. If the mutex already exists, then that code must already be running, so exit, otherwise, run. Couldn't be simpler. By using this particular overload of the constructor, we don't even need to worry about releasing the mutex at the end of the program.

Categories: C# | CodeProject
Posted by Williarob on Monday, October 04, 2010 5:57 AM
Permalink | Comments (0) | Post RSSRSS comment feed

Process and Thread Basics

Programs, Processes and Threads

In .NET terms, a program can be defined as an assembly, or group of assemblies, that work together to accomplish a task. Assemblies are little more than a way of packaging instructions into maintainable elements and are generally compiled into a dynamic link library (DLL) or an executable (EXE), or a combination of the two.

A process gives a program a place to run, allowing access to memory and resources. Generally, each process runs relatively independent of other processes. In particular, the memory where your program variables will reside is completely separate from the memory used by other processes. Your email program cannot directly assign a new value to a variable in the web browser program. If your email program can communicate with your web browser—for instance, to have it open a web page from a link you received in email—it does so with some form of communication that takes much more time than a memory access.

By putting programs into processes and using only a restricted, mutually agreed-upon communication between them has a number of advantages. One of the advantages is that an error in one process will be less likely to interfere with other processes. Before multitasking operating systems, it was much more common for a single program to be able to crash the entire machine. Putting tasks into processes, and limiting interaction with other processes and the operating system, has greatly added to system stability.

All modern operating systems support the subdivision of processes into multiple threads of execution. Threads run independently, like processes, and no thread knows what other threads are running or where they are in the program unless they synchronize explicitly. The key difference between threads and processes is that the threads within a process share all the data of the process. Thus, a simple memory access can accomplish the task of setting a variable in another thread. Every program will have at least one thread.

In his book ".NET Multithreading" Alan Dennis compares a Process to a house and a thread to a housecat. He writes:

The cat spends most of its time sleeping, but occasionally it wakes up and performs some action, such as eating. The house shares many characteristics with a process. It contains resources available to beings in it, such as a litter box. These resources are available to things within the house, but generally not to things outside the house. Things in the house are protected from things outside of the house. This level of isolation helps protect resources from misuse. One house can easily be differentiated from another by examining its address. Most important, houses contain things, such as furniture, litter boxes, and cats.

Cats perform actions. A cat interacts with elements in its environment, like the house it lives in. A housecat generally has a name. This helps identify it from other cats that might share the same household. It has access to some or the entire house depending on its owner’s permission. A thread’s access to elements may also be restricted based on permissions, in this case, the system’s security settings.

Multitasking

Multitasking means that more than one program can be active at a time. You may take it for granted that you can have an email program and a web browser program running at the same time. Yet, not that long ago, this was not the case. In the days of DOS you would need to save and close your spreadsheet before opening your word processor. With the advent of Windows, you could open multiple applications at once. Windows 3.x used something called Cooperative Multitasking which is based on the assumption that all running processes will yield control to the operating system at a frequent interval. The problem with this model was that not all software developers followed these rules and a program that did not return control to the system, or did so very infrequently, could destabilize the operating system, causing it to "lock up". When Windows 3.x started a new application, that application was invoked from the main thread. Windows passed control to the application with the understanding that control would quickly be returned to windows. If that didn't happen, all other running applications including the operating system could no longer execute instructions. Today, Windows employs Preemptive Multitasking. In this model, instead of relying on programs to return control to the system at regular intervals, the OS simply takes it. 

The main thread of a typical windows program executes a loop (Called a message pump). The loop checks a message queue to see if there is work to do and if there is, it does the work. For example, when a user clicks on a button in a windows application the click event adds work to the message queue indicating which method should be executed. This method is of course known as an event handler. While the loop is executing an event handler, it cannot process additional messages. Multithreading (literally using more than one thread) is how we can work around this limitation. Instead of having the main thread that was assigned to this program do the time consuming work, we assign the work to a seperate thread and have it do the work.

There are a number of ways to create and manage these new threads - using System.Threading, creating a delegate method, implementing the Event Based Asynchronous Pattern, using waithandles, etc. and I intend to explore all of them future articles. In a single core processor, this execution on a separate thread would be periodically interrupted by the operating system to allow other threads a chance to get work done; but after decades in a world where most computers had only one central processing unit (CPU), we are now in a world where only "old" computers have one CPU. Multi-core processors are now the norm. Therefore, every software developer needs to Think Parallel.

Multithreading

Multithreading allows a process to overlap I/O and computation. One thread can execute while another thread is waiting for an I/O operation to complete. Multithreading makes a GUI (graphical user interface) more responsive. The thread that handles GUI events, such as mouse clicks and button presses, can create additional threads to perform long-running tasks in response to the events. This allows the event handler thread to respond to more GUI events. Multithreading can speed up performance through parallelism. A program that makes full use of two processors may run in close to half the time. However, this level of speedup usually cannot be obtained, due to the communication overhead required for coordinating the threads.


Posted by Williarob on Saturday, June 28, 2008 9:00 PM
Permalink | Comments (0) | Post RSSRSS comment feed