C # Thread Synchronization (3)-Mutex mutex

Source: Internet
Author: User
Tags mutex semaphore

What is a mutex

"Mutex" is the abbreviated form of the term "mutually exclusive (mutually exclusive)", which is the mutex amount. The mutex is similar to the monitor mentioned in the critical section, where only the line friend with the mutex has access to the resource, and because there is only one mutex object, it is determined that the shared resource will not be accessed by multiple threads at the same time in any case. The thread that currently occupies the resource should hand over the owning mutex after the task has been processed so that other threads can access the resource after it is acquired. Mutexes are more complex than critical sections, because the use of mutexes not only enables the secure sharing of resources in different threads of the same application, but also enables secure sharing of resources between threads in different applications. NET, a mutex is represented by a mutex class.

Go around a little way.

Before we start figuring out how to use the mutex, we're going to go around a little way back.

When reading books, we are exposed to mutual exclusion, semaphores, these things should be in the "Operating system" this section. So, in fact, the original result of these things is as an OS function exists. Take a look at the declaration of a mutex:

[ComVisibleAttribute (True)] Public sealed class Mutex:waithandle

    • There is a property on the class: ComVisibleAttribute (True), which indicates that the class member is exposed to COM members. Do not care about it, as long as you know that this thing and COM have a relationship, it is probably more dense with windows;
    • Mutex it has a parent class: WaitHandle

So we had to go a little farther and see Waithandel's statement:

[ComVisibleAttribute (true)] public abstract class Waithandle:marshalbyrefobject, IDisposable

WaitHandle implements an interface and inherits a parent class. IDisposable in C # thread synchronization (2)-critical section &monitor about using is simply mentioned in the digression, and there is no more talking here. Look at its parent class MarshalByRefObject:

The MarshalByRefObject class allows objects to be accessed across application domain boundaries in applications that support remoting.

......

Note : An application domain is a partition in which one or more applications reside in an operating system process. Communicate directly with objects in the same application domain. There are two ways to communicate objects in different application domains: one is to transfer copies of objects across application domain boundaries, and one is to use proxies to exchange messages.

MarshalByRefObject is the base class for objects that communicate across application domain boundaries by using proxies to exchange messages. ......

Well, the rest of the content doesn't have to be looked at, otherwise it's going too far. We now know that the mutex is a subclass of WaitHandle (secretly telling you that the EventWaitHandle, the semaphore semaphore that are to be mentioned later, and AutoResetEvent and ManualResetEvent are its grandchildren), WaitHandle, in turn, inherits from the MarshalByRefObject class, which has the ability to cross application domain boundaries in the operating system. So now we can get some conclusions:

    • A mutex is a class that encapsulates the Win32 API, which will directly invoke the "corresponding" part of the operating system, whereas monitor does not inherit from any parent class, relatively speaking. NET own "native" (Of course. NET will ultimately depend on the runtime to invoke the various APIs of the operating system). Compared to monitor, you can think of a mutex as a shell about the Win32 mutex API.
    • A mutex can be used across application/application domains and therefore can be utilized for communication and mutual exclusion between application domains/applications; monitor, as we have seen so far, can only communicate between threads within the application. In fact, if the object used for the lock derives from Marshalbyrefobject,monitor, it can also provide locking in multiple application domains.
    • Mutexes are much more expensive to execute because of the need to invoke operating system resources, so if you only need to synchronize operations between threads within the application, Monitor/lock should be preferred.

Kind of like monitor? Better when it's lock.

Well, it's finally around. To see how to use mutexes.

  • WaitOne () / WaitOne (Int32, Boolean) / WaitOne (TimeSpan, Boolean): Request ownership, which is blocked until the current mutex receives a signal. or until the optional time-out interval is reached. These methods look similar to the Wait () method and its overloads on monitor, except that you do not need to provide a lock object as a parameter. But don't misunderstand,WaitOne () is essentially equivalent to Monitor.Enter ()/tryenter () rather than monitor.wait ()! This is because this waitone () does not have the means to release the current mutex after acquiring control like Monitor.Wait () and then block itself.
  • ReleaseMutex (): Releases the current Mutex once. Note that this is emphasized once because the thread that owns the mutex can repeatedly invoke the wait series function without preventing it from executing; this is the same as the Enter ()/exit () of monitor, which can be called repeatedly after acquiring an object lock. The number of times a mutex is invoked is saved by the common language runtime (CLR), and every WaitOne () counts +1 at a time, 1 per ReleaseMutex (), and as long as the count is not 0, the other mutex's waiting will assume that the mutex has not been released. There is no way to obtain the mutex. Also, as with Monitor.Exit (), only the owner of the mutex can Rleasemutex (), otherwise an exception is thrown.
  • If a thread terminates while owning a mutex, we call this mutex abandoned (abandoned). On MSDN, Microsoft warns that this is a "serious" programming error. This is to say that the owner of the mutex, after acquiring ownership, WaitOne () and Relasemutex () the wrong number of times, the caller itself is not responsible for the abort, causing the resource that the mutex is protecting may be in an inconsistent state. In fact, this is nothing more than reminding you to remember to use mutexes in the try/finally structure.

Recall the scenario we mentioned in "C # thread synchronization (2)-critical section &monitor" for producers and consumers, because these two functions are not equivalent to the wait () and pulse () of Monitor, so only this ReleaseMutex () and WaitOne () Two method mutexes cannot be applied to our example.

Of course, there are some other methods for synchronizing notifications on Mutext, but they are static methods on the WaitHandle of their parent class. So they are not deliberately "tailor-made" for mutexes, and there is some non-alignment with the way mutexes are used (you can try to replace the monitor with a mutex to achieve our previous scenario), or the mutex is actually somewhat reluctant to have these methods. We will discuss the issue of mutexes and notifications in more detail in the next blog about EventWaitHandle. Let's take a moment here and borrow the example from MSDN to simply illustrate the simplest application scenario for a mutex:

This example shows how a Mutex was used to synchronize access//to a protected resource. Unlike Monitor, Mutex can be used with//WaitHandle.WaitAll and WaitAny, and can be passed across//AppDomain boundaries .
Using System; using system.threading;
Class Test {

Create a new Mutex.    The creating thread does not own the //Mutex.

Private static Mutex mut = new mutex ();  

Private const int numiterations = 1;  

Private const int numthreads = 3;
static void Main ()

{         

Create the threads that would use the protected resource.

for (int i = 0; i < numthreads; i++)

{

Thread myThread = new thread (new ThreadStart (MyThreadProc));

Mythread.name = String.Format ("thread{0}", i + 1);

Mythread.start ();

}
//The main thread exits, but the application continues to

Run until all foreground threads has exited.

}
private static void MyThreadProc ()

{

for (int i = 0; i < numiterations; i++)

{

Useresource ();

}

}
//This method represents a resource the must be synchronized

So, only one thread at a time can enter.

Private static void Useresource ()

{         

Wait until it is safe to enter.

Mut. WaitOne ();
Console.WriteLine ("{0} have entered the protected area",

Thread.CurrentThread.Name);
//Place code to access non-reentrant resources here.
//simulate some work.

Thread.Sleep (500);
Console.WriteLine ("{0} is leaving the protected area\r\n",

Thread.CurrentThread.Name);

//Release the Mutex.

Mut. ReleaseMutex ();

}

}

Although this is just a schematic example, I still have to show contempt for Microsoft because this example does not use try/finally to guarantee ReleaseMutex execution. For a beginner, the first example can always affect the habit of the person, so is it possible to "simply" show a code that is sufficiently prescriptive for everyone while simply signaling it? Not to mention a considerable part of the people are directly copy sample code ... While cautioning everyone abandoned mutexes harm, while giving an exception can easily lead to this error sample,msdn not to be taken a closer look.

I have to say that the role of a mutex is to say that it is more like lock than Monitor, because it is only equivalent to Monitro.enter ()/exit (), except that the lock requested by the mutex is itself. Because of this, a mutex can also be a must (otherwise where does the lock come from?) ) is instantiated, not like Monitor is a static class, and cannot have its own instance.

Global and local mutexes

If you are using a mutex within an application domain, it would be better to use Monitor/lock directly, as the mutex previously mentioned requires a greater overhead and slower execution. However, the mutex is not monitor/lock after all, it is intended to be used for synchronization between processes.

In addition to the constructors that do not have parameters in the example code above, mutexes can be created by other constructors:

  • Mutex (): a mutex obtained with a parameterless constructor has no name, and the process cannot share the data in the form of a variable, so a mutex without a name is also called a local (local) mutex. In addition, the creation of the mutex, the creator does not have ownership of this instance, still need to call WaitOne () to request ownership.
  • Mutex (Boolean initiallyowned): Like the above constructor, it can only create local mutexes without names and cannot be used for inter-process synchronization. The Boolean parameter specifies whether ownership is acquired immediately after the creator creates the mutex, so the mutex (false) is equivalent to the mutex ().
  • Mutex (Boolean initiallyowned, String name): In this constructor we can also give a name to the mutex, in addition to the ability to specify whether the initial ownership is obtained after creation. Only this named mutex can be used by programs in other application domains, so this mutex is also called a global mutex. If string is null or an empty string, then this is equivalent to creating an unnamed mutex. Because there may be other programs before you create a mutex with the same name, the returned mutex instance may simply point to a mutex of the same name. However, this constructor does not have any mechanism to tell us the situation. Therefore, if you want to create a named mutex and expect to know whether the mutex was created by you, it is best to use any of the following two constructors. Finally, note that name is case-sensitive .
  • Mutex (Boolean initiallyowned, String name, out Boolean creatednew): The first two arguments are the same as the above constructor, and the third out parameter is used to indicate whether the initial ownership was obtained. This constructor should be used more in practice.
  • Mutex (Boolean initiallyowned, String name, out Booldan creatednew, mutexsecurity): The more this mutexsecurity parameter, is also determined by the nature of the global mutex. Because it can be accessed within the scope of the operating system, it raises security concerns about access, such as which Windows account running programs can access the mutex, whether the Mutext can be modified, and so on. Regarding the security of the mutex, it is not intended to be introduced in detail here, so it should be easy to see.

In addition, the mutex has two overloaded openexisting () methods to open a mutex that already exists.

Purpose of the mutex

As mentioned earlier, mutexes are not suitable for synchronization with mutual message notifications, and we have repeatedly mentioned that local mutexes should be replaced by Monitor/lock, while the synchronization of cross-application, inter-message notifications is eventwaitehandle/ Autoresetevent/manualresetevent bear more appropriate. Therefore, the scenarios that mutexes apply in. NET do not seem to be many. However, mutexes have one of the most common uses: to control that only one instance of an application can run.

Using System; using system.threading;
Class Mutexsample

{

private static Mutex mutex = NULL; Set as static member to hold a mutex throughout the program life cycle

static void Main ()

{

BOOL Firstinstance;

Mutex = new Mutex (true, @ "Global\mutexsampleapp", out firstinstance);

Try

{

if (!firstinstance)

{

Console.WriteLine ("An existing instance is running, enter exit ...");

Console.ReadLine ();

Return

}

Else

{

Console.WriteLine ("We are the first instance!") ");

for (int i=60; i > 0; i.)

{

Console.WriteLine (i);

Thread.Sleep (1000);

}

}

}

Finally

{

Only the first instance gains control, so ReleaseMutex is required only in this case, otherwise an exception is thrown.

if (firstinstance)

{

Mutex. ReleaseMutex ();

}

Mutex. Close ();

Mutex = null;

}

}

}

This is a console program, you can try to run more than one program at a time after compiling, the result of course is always only one program in the countdown timer. You might find other ways to implement the application's singleton on the internet, such as using process to find the name of the processes, how to find forms using the Win32 API FindWindow, and so on, but none of these methods guarantee absolute singleton. Because multiple processes and multithreading are the same, due to the random allocation of CPU time slices, multiple processes may be detected at the same time that no other instance is running. This is easy to do in the case of a busy CPU, such as a real-world example of a proud browser. Even if you set up only allow one instance to run, when the system is busy, as long as you try to open the browser multiple times, it is possible to "lucky" open a number of independent browser windows.

Remember, to implement a singleton for your application, you need to maintain the mutex throughout the entire application run, not just in the initial phase of the program. So, the creation and destruction code of the mutex in the example wraps the entire main () function.

Two details to note when using a mutex

    1. You may have noticed, in the example, that a "global\" prefix is given in the string named for the mutex. This is because on a server running Terminal Services (or Remote Desktop), a named global mutex has two kinds of visibility. If the name begins with the prefix "global\", the mutex is visible in all Terminal Server sessions. If the name begins with the prefix "local\", the mutex is visible only in the Terminal Server session in which it was created, in which case each other Terminal Server session on the server can have a separate mutex with the same name. If you do not specify a prefix when you create a named mutex, it takes the prefix "local\". In a Terminal Server session, only two mutexes with different name prefixes are separate mutexes, and these two mutexes are visible to all processes in a Terminal Server session. That is, the prefix name "global\" and "local\" are used only to describe the scope of the mutex name relative to the Terminal Server session (not relative to the process). Finally, it is important to note that "global\" and "local\" are case-sensitive.
    2. Since the parent class implements the Idisposalble interface, it is necessary that you manually release those unmanaged resources. So you have to call the close () method using try/finally, or my annoying using, to release all the resources that the mutex occupies!

Off topic:  

Strangely, the parent of the mutex WaitHandle implements the IDisposable, but we cannot find the Dispose () method on the mutex, for this reason we use close () in the last code to release the resource that the mutex occupies.   In fact, the close () here is equivalent to Dispose (), but why is this? Looking at WaitHandle again, we find that the Disopose () method It implements is protected, so we have no way to invoke it directly. And it exposes a close () method for the caller to replace Dispose (), so there is only close () on the mutex.   But why is that? Saying. NET was originally created by Microsoft from Borland Company, which is the father of Delphi. People familiar with Delphi know that the method used to release resources in the Object Pascal Framework is Dispose (), so Dispose () becomes.   NET Framework of an important member. Semantically, however, "Close" for resources such as files and network connections is more consistent with our habits than "Dispose". So "considerate" Microsoft is more "comfortable" for the user (the person who writes the code), and in this semantically more suitable for close resources, always provides a public implementation of close () as Disopose (). In fact, the inside of close () is just a direct call to Dispose ().   For this kind of practice, I really feel that some superfluous, in the end, how to make a thing how changeable to be willing to stop? If you really like Dispose (), then you can use an upward transformation ((IDisposable) ((WaitHandle) mutex). Dispose () to find it out. That is, forcing the mutex to convert to WaitHandle, then WaitHandle to IDisposable, and Dispose () on IDisposable is public. But we're not sure if the mutex and WaitHandle's close () are actually adding any logic at the time of the override, so it's okay to use Close ().

C # Thread Synchronization (3)-Mutex mutex

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.