Mutex 构造函数
定义
重要
一些信息与预发行产品相关,相应产品在发行之前可能会进行重大修改。 对于此处提供的信息,Microsoft 不作任何明示或暗示的担保。
初始化 Mutex 类的新实例。
重载
Mutex() |
使用默认属性初始化 Mutex 类的新实例。 |
Mutex(Boolean) |
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权)初始化 Mutex 类的新实例。 |
Mutex(Boolean, String) |
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称)初始化 Mutex 类的新实例。 |
Mutex(Boolean, String, Boolean) |
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权的 Boolean 值初始化 Mutex 类的新实例。 |
Mutex(Boolean, String, Boolean, MutexSecurity) |
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权以及访问控制安全是否已应用到命名互斥体的 Boolean 变量初始化 Mutex 类的新实例。 |
Mutex()
使用默认属性初始化 Mutex 类的新实例。
public:
Mutex();
public Mutex ();
Public Sub New ()
示例
下面的代码示例演示如何使用本地 Mutex 对象来同步对受保护资源的访问。 创建互斥体的线程最初不拥有它。
// This example shows how a Mutex is 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 namespace System;
using namespace System::Threading;
const int numIterations = 1;
const int numThreads = 3;
ref class Test
{
public:
// Create a new Mutex. The creating thread does not own the
// Mutex.
static Mutex^ mut = gcnew Mutex;
static void MyThreadProc()
{
for ( int i = 0; i < numIterations; i++ )
{
UseResource();
}
}
private:
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
static void UseResource()
{
//Wait until it is OK to enter.
mut->WaitOne();
Console::WriteLine( "{0} has entered protected the area", Thread::CurrentThread->Name );
// Place code to access non-reentrant resources here.
// Simulate some work.
Thread::Sleep( 500 );
Console::WriteLine( "{0} is leaving protected the area\r\n", Thread::CurrentThread->Name );
// Release the Mutex.
mut->ReleaseMutex();
}
};
int main()
{
// Create the threads that will use the protected resource.
for ( int i = 0; i < numThreads; i++ )
{
Thread^ myThread = gcnew Thread( gcnew ThreadStart( Test::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 have exited.
}
// This example shows how a Mutex is 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 Test13
{
// 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 will 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 have exited.
}
private static void MyThreadProc()
{
for(int i = 0; i < numIterations; i++)
{
UseResource();
}
}
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
mut.WaitOne();
Console.WriteLine("{0} has 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();
}
}
' This example shows how a Mutex is 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.
Imports System.Threading
Class Test
' Create a new Mutex. The creating thread does not own the
' Mutex.
Private Shared mut As New Mutex()
Private Const numIterations As Integer = 1
Private Const numThreads As Integer = 3
<MTAThread> _
Shared Sub Main()
' Create the threads that will use the protected resource.
Dim i As Integer
For i = 1 To numThreads
Dim myThread As New Thread(AddressOf MyThreadProc)
myThread.Name = [String].Format("Thread{0}", i)
myThread.Start()
Next i
' The main thread exits, but the application continues to
' run until all foreground threads have exited.
End Sub
Private Shared Sub MyThreadProc()
Dim i As Integer
For i = 1 To numIterations
UseResource()
Next i
End Sub
' This method represents a resource that must be synchronized
' so that only one thread at a time can enter.
Private Shared Sub UseResource()
' Wait until it is safe to enter.
mut.WaitOne()
Console.WriteLine("{0} has entered protected area", _
Thread.CurrentThread.Name)
' Place code to access non-reentrant resources here.
' Simulate some work
Thread.Sleep(500)
Console.WriteLine("{0} is leaving protected area" & vbCrLf, _
Thread.CurrentThread.Name)
' Release Mutex.
mut.ReleaseMutex()
End Sub
End Class
注解
调用此构造函数重载与调用 Mutex(Boolean) 构造函数重载和指定 false
互斥体的初始所有权相同。 也就是说,调用线程不拥有互斥体。
另请参阅
适用于
Mutex(Boolean)
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权)初始化 Mutex 类的新实例。
public:
Mutex(bool initiallyOwned);
public Mutex (bool initiallyOwned);
new System.Threading.Mutex : bool -> System.Threading.Mutex
Public Sub New (initiallyOwned As Boolean)
参数
- initiallyOwned
- Boolean
如果给调用线程赋予互斥体的初始所属权,则为 true
;否则为 false
。
示例
下面的代码示例演示如何使用本地 Mutex 对象来同步对受保护资源的访问。 最初创建 Mutex 自己的线程。
using namespace System;
using namespace System::Threading;
const int numIterations = 1;
const int numThreads = 3;
ref class Test
{
public:
// Create a new Mutex. The creating thread owns the
// Mutex.
static Mutex^ mut = gcnew Mutex( true );
static void MyThreadProc()
{
for ( int i = 0; i < numIterations; i++ )
{
UseResource();
}
}
private:
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
static void UseResource()
{
//Wait until it is OK to enter.
mut->WaitOne();
Console::WriteLine( "{0} has entered protected the area", Thread::CurrentThread->Name );
// Place code to access non-reentrant resources here.
// Simulate some work.
Thread::Sleep( 500 );
Console::WriteLine( "{0} is leaving protected the area\r\n", Thread::CurrentThread->Name );
// Release the Mutex.
mut->ReleaseMutex();
}
};
int main()
{
// Initialize the Mutex.
Mutex^ mut = Test::mut;
// Create the threads that will use the protected resource.
for ( int i = 0; i < numThreads; i++ )
{
Thread^ myThread = gcnew Thread( gcnew ThreadStart( Test::MyThreadProc ) );
myThread->Name = String::Format( "Thread {0}", i + 1 );
myThread->Start();
}
// Wait one second before allowing other threads to
// acquire the Mutex.
Console::WriteLine( "Creating thread owns the Mutex." );
Thread::Sleep( 1000 );
Console::WriteLine( "Creating thread releases the Mutex.\r\n" );
mut->ReleaseMutex();
}
// The example displays output like the following:
// Creating thread owns the Mutex.
// Creating thread releases the Mutex.
//
// Thread1 has entered the protected area
// Thread1 is leaving the protected area
//
// Thread2 has entered the protected area
// Thread2 is leaving the protected area
//
// Thread3 has entered the protected area
// Thread3 is leaving the protected area
using System;
using System.Threading;
class Test
{
private static Mutex mut;
private const int numIterations = 1;
private const int numThreads = 3;
static void Main()
{
// Create a new Mutex. The creating thread owns the Mutex.
mut = new Mutex(true);
// Create the threads that will 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();
}
// Wait one second before allowing other threads to
// acquire the Mutex.
Console.WriteLine("Creating thread owns the Mutex.");
Thread.Sleep(1000);
Console.WriteLine("Creating thread releases the Mutex.\r\n");
mut.ReleaseMutex();
}
private static void MyThreadProc()
{
for(int i = 0; i < numIterations; i++)
{
UseResource();
}
}
// This method represents a resource that must be synchronized
// so that only one thread at a time can enter.
private static void UseResource()
{
// Wait until it is safe to enter.
mut.WaitOne();
Console.WriteLine("{0} has 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();
}
}
// The example displays output like the following:
// Creating thread owns the Mutex.
// Creating thread releases the Mutex.
//
// Thread1 has entered the protected area
// Thread1 is leaving the protected area
//
// Thread2 has entered the protected area
// Thread2 is leaving the protected area
//
// Thread3 has entered the protected area
// Thread3 is leaving the protected area
Imports System.Threading
Class Test
' Create a new Mutex. The creating thread owns the
' Mutex.
Private Shared mut As New Mutex(True)
Private Const numIterations As Integer = 1
Private Const numThreads As Integer = 3
<MTAThread> _
Shared Sub Main()
' Create the threads that will use the protected resource.
Dim i As Integer
For i = 1 To numThreads
Dim myThread As New Thread(AddressOf MyThreadProc)
myThread.Name = [String].Format("Thread{0}", i)
myThread.Start()
Next i
' Wait one second before allowing other threads to
' acquire the Mutex.
Console.WriteLine("Creating thread owns the Mutex.")
Thread.Sleep(1000)
Console.WriteLine("Creating thread releases the Mutex." & vbCrLf)
mut.ReleaseMutex()
End Sub
Private Shared Sub MyThreadProc()
Dim i As Integer
For i = 1 To numIterations
UseResource()
Next i
End Sub
' This method represents a resource that must be synchronized
' so that only one thread at a time can enter.
Private Shared Sub UseResource()
' Wait until it is safe to enter.
mut.WaitOne()
Console.WriteLine("{0} has entered protected area", _
Thread.CurrentThread.Name)
' Place code to access non-reentrant resources here.
' Simulate some work
Thread.Sleep(500)
Console.WriteLine("{0} is leaving protected area" & vbCrLf, _
Thread.CurrentThread.Name)
' Release Mutex.
mut.ReleaseMutex()
End Sub
End Class
' The example displays output like the following:
' Creating thread owns the Mutex.
' Creating thread releases the Mutex.
'
' Thread1 has entered the protected area
' Thread1 is leaving the protected area
'
' Thread2 has entered the protected area
' Thread2 is leaving the protected area
'
' Thread3 has entered the protected area
' Thread3 is leaving the protected area
另请参阅
适用于
Mutex(Boolean, String)
使用 Boolean 值(指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称)初始化 Mutex 类的新实例。
public:
Mutex(bool initiallyOwned, System::String ^ name);
[System.Security.SecurityCritical]
public Mutex (bool initiallyOwned, string name);
public Mutex (bool initiallyOwned, string? name);
public Mutex (bool initiallyOwned, string name);
[<System.Security.SecurityCritical>]
new System.Threading.Mutex : bool * string -> System.Threading.Mutex
new System.Threading.Mutex : bool * string -> System.Threading.Mutex
Public Sub New (initiallyOwned As Boolean, name As String)
参数
- initiallyOwned
- Boolean
如果为 true
,则给予调用线程已命名的系统互斥体的初始所属权(如果已命名的系统互斥体是通过此调用创建的);否则为 false
。
- name
- String
如果要与其他进程共享同步对象,则为名称;否则为 null
或空字符串。 该名称区分大小写。
- 属性
例外
命名互斥体存在且具有访问控制安全性,但用户不具备 FullControl。
name
无效。 导致这种情况的原因有很多,包括操作系统可能会施加的一些限制,例如未知前缀或无效字符。 请注意,名称和常见前缀 "Global" 和 "Local" 区分大小写。
或
还有其他错误。 HResult
属性可能提供更多信息。
仅限 Windows:name
指定了未知命名空间。 有关详细信息,请参阅对象名称。
name
太长。 长度限制可能取决于操作系统或配置。
无法创建具有提供的 name
的同步对象。 不同类型的同步对象可能具有相同的名称。
仅限 .NET Framework:name
的长度超过 MAX_PATH(260 个字符)。
示例
以下示例演示如何使用命名互斥体在两个单独的进程中运行的线程之间发出信号。
从两个或更多个命令窗口运行此程序。 每个进程创建一个 Mutex 表示命名互斥体 MyMutex
的对象。 命名互斥体是一个系统对象,其生存期由表示它的对象的生存期 Mutex 绑定。 当第一个进程创建其 Mutex 对象时,将创建命名互斥体;在此示例中,命名互斥体由运行程序的第一个进程拥有。 当表示命名互斥体的所有 Mutex 对象都已释放时,将销毁命名互斥体。
此示例中使用的构造函数重载无法告诉调用线程是否授予了命名互斥体的初始所有权。 除非可以确定线程将创建命名互斥体,否则不应使用此构造函数请求初始所有权。
using namespace System;
using namespace System::Threading;
int main()
{
// Create the named mutex. Only one system object named
// "MyMutex" can exist; the local Mutex object represents
// this system object, regardless of which process or thread
// caused "MyMutex" to be created.
Mutex^ m = gcnew Mutex( false,"MyMutex" );
// Try to gain control of the named mutex. If the mutex is
// controlled by another thread, wait for it to be released.
Console::WriteLine( "Waiting for the Mutex." );
m->WaitOne();
// Keep control of the mutex until the user presses
// ENTER.
Console::WriteLine( "This application owns the mutex. "
"Press ENTER to release the mutex and exit." );
Console::ReadLine();
m->ReleaseMutex();
}
using System;
using System.Threading;
public class Test1
{
public static void Main()
{
// Create the named mutex. Only one system object named
// "MyMutex" can exist; the local Mutex object represents
// this system object, regardless of which process or thread
// caused "MyMutex" to be created.
Mutex m = new Mutex(false, "MyMutex");
// Try to gain control of the named mutex. If the mutex is
// controlled by another thread, wait for it to be released.
Console.WriteLine("Waiting for the Mutex.");
m.WaitOne();
// Keep control of the mutex until the user presses
// ENTER.
Console.WriteLine("This application owns the mutex. " +
"Press ENTER to release the mutex and exit.");
Console.ReadLine();
m.ReleaseMutex();
}
}
Imports System.Threading
Public Class Test
Public Shared Sub Main()
' Create the named mutex. Only one system object named
' "MyMutex" can exist; the local Mutex object represents
' this system object, regardless of which process or thread
' caused "MyMutex" to be created.
Dim m As New Mutex(False, "MyMutex")
' Try to gain control of the named mutex. If the mutex is
' controlled by another thread, wait for it to be released.
Console.WriteLine("Waiting for the Mutex.")
m.WaitOne()
' Keep control of the mutex until the user presses
' ENTER.
Console.WriteLine("This application owns the mutex. " _
& "Press ENTER to release the mutex and exit.")
Console.ReadLine()
m.ReleaseMutex()
End Sub
End Class
注解
name
可以是前缀Global\``Local\
,也可以指定命名空间。 Global
指定命名空间时,同步对象可以与系统上的任何进程共享。 Local
指定命名空间时,该命名空间也是未指定命名空间时的默认值,同步对象可以与同一会话中的进程共享。 在Windows,会话是登录会话,服务通常在不同的非交互式会话中运行。 在类似 Unix 的操作系统上,每个 shell 都有其自己的会话。 会话本地同步对象可能适合在进程与父/子关系之间同步,它们都在同一会话中运行。 有关Windows上的同步对象名称的详细信息,请参阅对象名称。
如果提供了请求 name
类型的同步对象并且请求的同步对象已存在于命名空间中,则使用现有同步对象。 如果命名空间中已存在不同类型的同步对象,则会引发一个 WaitHandleCannotBeOpenedException
。 否则,将创建一个新的同步对象。
如果 name
不是 null
且 initiallyOwned
不是 true
,则调用线程仅当由于此调用而创建命名的系统互斥体时,调用线程才拥有互斥体。 由于没有用于确定是否已创建命名系统互斥体的机制,因此最好在调用此构造函数重载时指定false``initiallyOwned
该机制。 如果需要确定初始所有权, Mutex(Boolean, String, Boolean) 可以使用构造函数。
此构造函数初始化表示 Mutex 命名系统互斥体的对象。 可以创建表示同一命名系统互斥体的多个 Mutex 对象。
如果已使用访问控制安全性创建了命名互斥体,并且调用方没有 MutexRights.FullControl,则会引发异常。 若要打开仅具有同步线程活动所需的权限的现有命名互斥体,请参阅 OpenExisting 该方法。
如果指定 null
或为 name
空字符串,则会创建本地互斥体,就像调用构造 Mutex(Boolean) 函数一样。 在这种情况下, createdNew
始终 true
为 .
由于它们是系统范围的,因此命名互斥体可用于协调跨进程边界的资源使用。
备注
在运行终端服务的服务器上,命名的系统互斥体可以具有两个级别的可见性。 如果名称以前缀“Global\”开头,则互斥体在所有终端服务器会话中可见。 如果名称以前缀“Local\”开头,则互斥体仅在创建它的终端服务器会话中可见。 在这种情况下,服务器上的其他每个终端服务器会话中都可以存在具有相同名称的单独互斥体。 如果在创建命名互斥体时未指定前缀,则它采用前缀“Local\”。 在终端服务器会话中,两个名称只与其前缀不同的互斥体是单独的互斥体,并且两者都对终端服务器会话中的所有进程可见。 也就是说,前缀名称“Global\”和“Local\”描述互斥体名称相对于终端服务器会话的范围,而不是相对于进程。
反斜杠 (\) 是互斥体名称中的保留字符。 请勿在互斥体名称中使用反斜杠 (\),除非在终端服务器会话中使用互斥体的注释中另有规定。 否则,即使互斥体的名称表示现有文件,也可能引发 DirectoryNotFoundException。
另请参阅
适用于
Mutex(Boolean, String, Boolean)
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权的 Boolean 值初始化 Mutex 类的新实例。
public:
Mutex(bool initiallyOwned, System::String ^ name, [Runtime::InteropServices::Out] bool % createdNew);
[System.Security.SecurityCritical]
public Mutex (bool initiallyOwned, string name, out bool createdNew);
public Mutex (bool initiallyOwned, string? name, out bool createdNew);
public Mutex (bool initiallyOwned, string name, out bool createdNew);
[<System.Security.SecurityCritical>]
new System.Threading.Mutex : bool * string * bool -> System.Threading.Mutex
new System.Threading.Mutex : bool * string * bool -> System.Threading.Mutex
Public Sub New (initiallyOwned As Boolean, name As String, ByRef createdNew As Boolean)
参数
- initiallyOwned
- Boolean
如果为 true
,则给予调用线程已命名的系统互斥体的初始所属权(如果已命名的系统互斥体是通过此调用创建的);否则为 false
。
- name
- String
如果要与其他进程共享同步对象,则为名称;否则为 null
或空字符串。 该名称区分大小写。
- createdNew
- Boolean
在此方法返回时,如果创建了局部互斥体(即,如果 name
为 null
或空字符串)或指定的命名系统互斥体,则包含布尔值 true
;如果指定的命名系统互斥体已存在,则为 false
。 此参数未经初始化即被传递。
- 属性
例外
命名互斥体存在且具有访问控制安全性,但用户不具备 FullControl。
name
无效。 导致这种情况的原因有很多,包括操作系统可能会施加的一些限制,例如未知前缀或无效字符。 请注意,名称和常见前缀 "Global" 和 "Local" 区分大小写。
或
还有其他错误。 HResult
属性可能提供更多信息。
仅限 Windows:name
指定了未知命名空间。 有关详细信息,请参阅对象名称。
name
太长。 长度限制可能取决于操作系统或配置。
无法创建具有提供的 name
的同步对象。 不同类型的同步对象可能具有相同的名称。
仅限 .NET Framework:name
的长度超过 MAX_PATH(260 个字符)。
示例
下面的代码示例演示如何使用命名互斥体在进程或线程之间发出信号。 从两个或更多个命令窗口运行此程序。 每个进程创建一个 Mutex 对象,该对象代表命名互斥体“MyMutex”。 命名互斥体是一个系统对象。 在此示例中,其生存期由表示它的对象的生存期 Mutex 绑定。 当第一个进程创建其本地 Mutex 对象时,将创建命名互斥体,并在表示它的所有 Mutex 对象都已发布时被销毁。 命名互斥体最初由第一个进程拥有。 第二个进程和任何后续进程等待早期进程释放命名互斥体。
// This example shows how a named mutex is used to signal between
// processes or threads.
// Run this program from two (or more) command windows. Each process
// creates a Mutex object that represents the named mutex "MyMutex".
// The named mutex is a system object whose lifetime is bounded by the
// lifetimes of the Mutex objects that represent it. The named mutex
// is created when the first process creates its local Mutex; in this
// example, the named mutex is owned by the first process. The named
// mutex is destroyed when all the Mutex objects that represent it
// have been released.
// The second process (and any subsequent process) waits for earlier
// processes to release the named mutex.
using namespace System;
using namespace System::Threading;
int main()
{
// Set this variable to false if you do not want to request
// initial ownership of the named mutex.
bool requestInitialOwnership = true;
bool mutexWasCreated;
// Request initial ownership of the named mutex by passing
// true for the first parameter. Only one system object named
// "MyMutex" can exist; the local Mutex object represents
// this system object. If "MyMutex" is created by this call,
// then mutexWasCreated contains true; otherwise, it contains
// false.
Mutex^ m = gcnew Mutex( requestInitialOwnership, "MyMutex", mutexWasCreated );
// This thread owns the mutex only if it both requested
// initial ownership and created the named mutex. Otherwise,
// it can request the named mutex by calling WaitOne.
if ( !(requestInitialOwnership && mutexWasCreated) )
{
Console::WriteLine( "Waiting for the named mutex." );
m->WaitOne();
}
// Once the process has gained control of the named mutex,
// hold onto it until the user presses ENTER.
Console::WriteLine( "This process owns the named mutex. "
"Press ENTER to release the mutex and exit." );
Console::ReadLine();
// Call ReleaseMutex to allow other threads to gain control
// of the named mutex. If you keep a reference to the local
// Mutex, you can call WaitOne to request control of the
// named mutex.
m->ReleaseMutex();
}
// This example shows how a named mutex is used to signal between
// processes or threads.
// Run this program from two (or more) command windows. Each process
// creates a Mutex object that represents the named mutex "MyMutex".
// The named mutex is a system object whose lifetime is bounded by the
// lifetimes of the Mutex objects that represent it. The named mutex
// is created when the first process creates its local Mutex; in this
// example, the named mutex is owned by the first process. The named
// mutex is destroyed when all the Mutex objects that represent it
// have been released.
// The second process (and any subsequent process) waits for earlier
// processes to release the named mutex.
using System;
using System.Threading;
public class Test12
{
public static void Main()
{
// Set this variable to false if you do not want to request
// initial ownership of the named mutex.
bool requestInitialOwnership = true;
bool mutexWasCreated;
// Request initial ownership of the named mutex by passing
// true for the first parameter. Only one system object named
// "MyMutex" can exist; the local Mutex object represents
// this system object. If "MyMutex" is created by this call,
// then mutexWasCreated contains true; otherwise, it contains
// false.
Mutex m = new Mutex(requestInitialOwnership,
"MyMutex",
out mutexWasCreated);
// This thread owns the mutex only if it both requested
// initial ownership and created the named mutex. Otherwise,
// it can request the named mutex by calling WaitOne.
if (!(requestInitialOwnership && mutexWasCreated))
{
Console.WriteLine("Waiting for the named mutex.");
m.WaitOne();
}
// Once the process has gained control of the named mutex,
// hold onto it until the user presses ENTER.
Console.WriteLine("This process owns the named mutex. " +
"Press ENTER to release the mutex and exit.");
Console.ReadLine();
// Call ReleaseMutex to allow other threads to gain control
// of the named mutex. If you keep a reference to the local
// Mutex, you can call WaitOne to request control of the
// named mutex.
m.ReleaseMutex();
}
}
' This example shows how a named mutex is used to signal between
' processes or threads.
' Run this program from two (or more) command windows. Each process
' creates a Mutex object that represents the named mutex "MyMutex".
' The named mutex is a system object whose lifetime is bounded by the
' lifetimes of the Mutex objects that represent it. The named mutex
' is created when the first process creates its local Mutex; in this
' example, the named mutex is owned by the first process. The named
' mutex is destroyed when all the Mutex objects that represent it
' have been released.
' The second process (and any subsequent process) waits for earlier
' processes to release the named mutex.
Imports System.Threading
Public Class Test
<MTAThread> _
Public Shared Sub Main()
' Set this variable to false if you do not want to request
' initial ownership of the named mutex.
Dim requestInitialOwnership As Boolean = True
Dim mutexWasCreated As Boolean
' Request initial ownership of the named mutex by passing
' true for the first parameter. Only one system object named
' "MyMutex" can exist; the local Mutex object represents
' this system object. If "MyMutex" is created by this call,
' then mutexWasCreated contains true; otherwise, it contains
' false.
Dim m As New Mutex(requestInitialOwnership, "MyMutex", _
mutexWasCreated)
' This thread owns the mutex only if it both requested
' initial ownership and created the named mutex. Otherwise,
' it can request the named mutex by calling WaitOne.
If Not (requestInitialOwnership And mutexWasCreated) Then
Console.WriteLine("Waiting for the named mutex.")
m.WaitOne()
End If
' Once the process has gained control of the named mutex,
' hold onto it until the user presses ENTER.
Console.WriteLine("This process owns the named mutex. " _
& "Press ENTER to release the mutex and exit.")
Console.ReadLine()
' Call ReleaseMutex to allow other threads to gain control
' of the named mutex. If you keep a reference to the local
' Mutex, you can call WaitOne to request control of the
' named mutex.
m.ReleaseMutex()
End Sub
End Class
注解
name
可以是前缀Global\``Local\
,也可以指定命名空间。 Global
指定命名空间时,同步对象可以与系统上的任何进程共享。 Local
指定命名空间时,该命名空间也是未指定命名空间时的默认值,同步对象可以与同一会话中的进程共享。 在Windows,会话是登录会话,服务通常在不同的非交互式会话中运行。 在类似 Unix 的操作系统上,每个 shell 都有其自己的会话。 会话本地同步对象可能适合在进程与父/子关系之间同步,它们都在同一会话中运行。 有关Windows上的同步对象名称的详细信息,请参阅对象名称。
如果提供了请求 name
类型的同步对象并且请求的同步对象已存在于命名空间中,则使用现有同步对象。 如果命名空间中已存在不同类型的同步对象,则会引发一个 WaitHandleCannotBeOpenedException
。 否则,将创建一个新的同步对象。
如果name
不是null
且initiallyOwned
不是true
,则调用线程仅在createdNew``true
调用后拥有命名互斥体。 否则,线程可以通过调用 WaitOne 方法请求互斥体。
此构造函数初始化表示 Mutex 命名系统互斥体的对象。 可以创建表示同一命名系统互斥体的多个 Mutex 对象。
如果已使用访问控制安全性创建了命名互斥体,并且调用方没有 MutexRights.FullControl 权限,则会引发异常。 若要打开仅具有同步线程活动所需的权限的现有命名互斥体,请参阅 OpenExisting 该方法。
如果指定 null
或为 name
空字符串,则会创建本地互斥体,就像调用构造 Mutex(Boolean) 函数一样。 在这种情况下, createdNew
始终 true
为 .
由于它们是系统范围的,因此命名互斥体可用于协调跨进程边界的资源使用。
备注
在运行终端服务的服务器上,命名的系统互斥体可以具有两个级别的可见性。 如果名称以前缀“Global\”开头,则互斥体在所有终端服务器会话中可见。 如果名称以前缀“Local\”开头,则互斥体仅在创建它的终端服务器会话中可见。 在这种情况下,服务器上的其他每个终端服务器会话中都可以存在具有相同名称的单独互斥体。 如果在创建命名互斥体时未指定前缀,则它采用前缀“Local\”。 在终端服务器会话中,两个名称只与其前缀不同的互斥体是单独的互斥体,并且两者都对终端服务器会话中的所有进程可见。 也就是说,前缀名称“Global\”和“Local\”描述互斥体名称相对于终端服务器会话的范围,而不是相对于进程。
反斜杠 (\) 是互斥体名称中的保留字符。 请勿在互斥体名称中使用反斜杠 (\),除非在终端服务器会话中使用互斥体的注释中另有规定。 否则,即使互斥体的名称表示现有文件,也可能引发 DirectoryNotFoundException。
另请参阅
适用于
Mutex(Boolean, String, Boolean, MutexSecurity)
使用可指示调用线程是否应具有互斥体的初始所有权以及字符串是否为互斥体的名称的 Boolean 值和当线程返回时可指示调用线程是否已赋予互斥体的初始所有权以及访问控制安全是否已应用到命名互斥体的 Boolean 变量初始化 Mutex 类的新实例。
public:
Mutex(bool initiallyOwned, System::String ^ name, [Runtime::InteropServices::Out] bool % createdNew, System::Security::AccessControl::MutexSecurity ^ mutexSecurity);
public Mutex (bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity);
[System.Security.SecurityCritical]
public Mutex (bool initiallyOwned, string name, out bool createdNew, System.Security.AccessControl.MutexSecurity mutexSecurity);
new System.Threading.Mutex : bool * string * bool * System.Security.AccessControl.MutexSecurity -> System.Threading.Mutex
[<System.Security.SecurityCritical>]
new System.Threading.Mutex : bool * string * bool * System.Security.AccessControl.MutexSecurity -> System.Threading.Mutex
Public Sub New (initiallyOwned As Boolean, name As String, ByRef createdNew As Boolean, mutexSecurity As MutexSecurity)
参数
- initiallyOwned
- Boolean
如果为 true
,则给予调用线程已命名的系统互斥体的初始所属权(如果已命名的系统互斥体是通过此调用创建的);否则为 false
。
- name
- String
如果要与其他进程共享同步对象,则为名称;否则为 null
或空字符串。 该名称区分大小写。
- createdNew
- Boolean
在此方法返回时,如果创建了局部互斥体(即,如果 name
为 null
或空字符串)或指定的命名系统互斥体,则包含布尔值 true
;如果指定的命名系统互斥体已存在,则为 false
。 此参数未经初始化即被传递。
- mutexSecurity
- MutexSecurity
一个 MutexSecurity 对象,表示应用于已命名的系统互斥体的访问控制安全性。
- 属性
例外
name
无效。 导致这种情况的原因有很多,包括操作系统可能会施加的一些限制,例如未知前缀或无效字符。 请注意,名称和常见前缀 "Global" 和 "Local" 区分大小写。
或
还有一些其他错误。 HResult
属性可能提供更多信息。
仅限 Windows:name
指定了未知命名空间。 有关详细信息,请参阅对象名称。
name
太长。 长度限制可能取决于操作系统或配置。
命名互斥体存在且具有访问控制安全性,但用户不具备 FullControl。
无法创建具有提供的 name
的同步对象。 不同类型的同步对象可能具有相同的名称。
仅限 .NET Framework:name
的长度超过 MAX_PATH(260 个字符)。
示例
下面的代码示例演示具有访问控制安全性的命名互斥体的跨进程行为。 此示例使用 OpenExisting(String) 方法重载测试命名互斥体是否存在。
如果互斥体不存在,则会使用初始所有权和访问控制安全性创建它,以拒绝当前用户使用互斥体的权利,但授予对互斥体读取和更改权限的权限。
如果从两个命令窗口运行编译的示例,则第二个副本将在调用 OpenExisting(String)时引发访问冲突异常。 捕获异常,该示例使用 OpenExisting(String, MutexRights) 方法重载打开互斥体,并具有读取和更改权限所需的权限。
更改权限后,将打开互斥体,并具有输入和释放它所需的权限。 如果从第三个命令窗口运行编译的示例,则使用新权限运行该示例。
using namespace System;
using namespace System::Threading;
using namespace System::Security::AccessControl;
using namespace System::Security::Permissions;
public ref class Example
{
public:
[SecurityPermissionAttribute(SecurityAction::Demand,Flags=SecurityPermissionFlag::UnmanagedCode)]
static void Main()
{
String^ mutexName = L"MutexExample4";
Mutex^ m = nullptr;
bool doesNotExist = false;
bool unauthorized = false;
// The value of this variable is set by the mutex
// constructor. It is true if the named system mutex was
// created, and false if the named mutex already existed.
//
bool mutexWasCreated = false;
// Attempt to open the named mutex.
try
{
// Open the mutex with (MutexRights.Synchronize |
// MutexRights.Modify), to enter and release the
// named mutex.
//
m = Mutex::OpenExisting( mutexName );
}
catch ( WaitHandleCannotBeOpenedException^ )
{
Console::WriteLine( L"Mutex does not exist." );
doesNotExist = true;
}
catch ( UnauthorizedAccessException^ ex )
{
Console::WriteLine( L"Unauthorized access: {0}", ex->Message );
unauthorized = true;
}
// There are three cases: (1) The mutex does not exist.
// (2) The mutex exists, but the current user doesn't
// have access. (3) The mutex exists and the user has
// access.
//
if ( doesNotExist )
{
// The mutex does not exist, so create it.
// Create an access control list (ACL) that denies the
// current user the right to enter or release the
// mutex, but allows the right to read and change
// security information for the mutex.
//
String^ user = String::Concat( Environment::UserDomainName, L"\\",
Environment::UserName );
MutexSecurity^ mSec = gcnew MutexSecurity;
MutexAccessRule^ rule = gcnew MutexAccessRule( user,
static_cast<MutexRights>(
MutexRights::Synchronize |
MutexRights::Modify),
AccessControlType::Deny );
mSec->AddAccessRule( rule );
rule = gcnew MutexAccessRule( user,
static_cast<MutexRights>(
MutexRights::ReadPermissions |
MutexRights::ChangePermissions),
AccessControlType::Allow );
mSec->AddAccessRule( rule );
// Create a Mutex object that represents the system
// mutex named by the constant 'mutexName', with
// initial ownership for this thread, and with the
// specified security access. The Boolean value that
// indicates creation of the underlying system object
// is placed in mutexWasCreated.
//
m = gcnew Mutex( true,mutexName, mutexWasCreated,mSec );
// If the named system mutex was created, it can be
// used by the current instance of this program, even
// though the current user is denied access. The current
// program owns the mutex. Otherwise, exit the program.
//
if ( mutexWasCreated )
{
Console::WriteLine( L"Created the mutex." );
}
else
{
Console::WriteLine( L"Unable to create the mutex." );
return;
}
}
else if ( unauthorized )
{
// Open the mutex to read and change the access control
// security. The access control security defined above
// allows the current user to do this.
//
try
{
m = Mutex::OpenExisting( mutexName,
static_cast<MutexRights>(
MutexRights::ReadPermissions |
MutexRights::ChangePermissions) );
// Get the current ACL. This requires
// MutexRights.ReadPermissions.
MutexSecurity^ mSec = m->GetAccessControl();
String^ user = String::Concat( Environment::UserDomainName,
L"\\", Environment::UserName );
// First, the rule that denied the current user
// the right to enter and release the mutex must
// be removed.
MutexAccessRule^ rule = gcnew MutexAccessRule( user,
static_cast<MutexRights>(
MutexRights::Synchronize |
MutexRights::Modify),
AccessControlType::Deny );
mSec->RemoveAccessRule( rule );
// Now grant the user the correct rights.
//
rule = gcnew MutexAccessRule( user,
static_cast<MutexRights>(
MutexRights::Synchronize |
MutexRights::Modify),
AccessControlType::Allow );
mSec->AddAccessRule( rule );
// Update the ACL. This requires
// MutexRights.ChangePermissions.
m->SetAccessControl( mSec );
Console::WriteLine( L"Updated mutex security." );
// Open the mutex with (MutexRights.Synchronize
// | MutexRights.Modify), the rights required to
// enter and release the mutex.
//
m = Mutex::OpenExisting( mutexName );
}
catch ( UnauthorizedAccessException^ ex )
{
Console::WriteLine(
L"Unable to change permissions: {0}", ex->Message );
return;
}
}
// If this program created the mutex, it already owns
// the mutex.
//
if ( !mutexWasCreated )
{
// Enter the mutex, and hold it until the program
// exits.
//
try
{
Console::WriteLine( L"Wait for the mutex." );
m->WaitOne();
Console::WriteLine( L"Entered the mutex." );
}
catch ( UnauthorizedAccessException^ ex )
{
Console::WriteLine( L"Unauthorized access: {0}",
ex->Message );
}
}
Console::WriteLine( L"Press the Enter key to exit." );
Console::ReadLine();
m->ReleaseMutex();
m->Dispose();
}
};
int main()
{
Example::Main();
}
using System;
using System.Threading;
using System.Security.AccessControl;
internal class Example
{
internal static void Main()
{
const string mutexName = "MutexExample4";
Mutex m = null;
bool doesNotExist = false;
bool unauthorized = false;
// The value of this variable is set by the mutex
// constructor. It is true if the named system mutex was
// created, and false if the named mutex already existed.
//
bool mutexWasCreated = false;
// Attempt to open the named mutex.
try
{
// Open the mutex with (MutexRights.Synchronize |
// MutexRights.Modify), to enter and release the
// named mutex.
//
m = Mutex.OpenExisting(mutexName);
}
catch(WaitHandleCannotBeOpenedException)
{
Console.WriteLine("Mutex does not exist.");
doesNotExist = true;
}
catch(UnauthorizedAccessException ex)
{
Console.WriteLine("Unauthorized access: {0}", ex.Message);
unauthorized = true;
}
// There are three cases: (1) The mutex does not exist.
// (2) The mutex exists, but the current user doesn't
// have access. (3) The mutex exists and the user has
// access.
//
if (doesNotExist)
{
// The mutex does not exist, so create it.
// Create an access control list (ACL) that denies the
// current user the right to enter or release the
// mutex, but allows the right to read and change
// security information for the mutex.
//
string user = Environment.UserDomainName + "\\"
+ Environment.UserName;
var mSec = new MutexSecurity();
MutexAccessRule rule = new MutexAccessRule(user,
MutexRights.Synchronize | MutexRights.Modify,
AccessControlType.Deny);
mSec.AddAccessRule(rule);
rule = new MutexAccessRule(user,
MutexRights.ReadPermissions | MutexRights.ChangePermissions,
AccessControlType.Allow);
mSec.AddAccessRule(rule);
// Create a Mutex object that represents the system
// mutex named by the constant 'mutexName', with
// initial ownership for this thread, and with the
// specified security access. The Boolean value that
// indicates creation of the underlying system object
// is placed in mutexWasCreated.
//
m = new Mutex(true, mutexName, out mutexWasCreated, mSec);
// If the named system mutex was created, it can be
// used by the current instance of this program, even
// though the current user is denied access. The current
// program owns the mutex. Otherwise, exit the program.
//
if (mutexWasCreated)
{
Console.WriteLine("Created the mutex.");
}
else
{
Console.WriteLine("Unable to create the mutex.");
return;
}
}
else if (unauthorized)
{
// Open the mutex to read and change the access control
// security. The access control security defined above
// allows the current user to do this.
//
try
{
m = Mutex.OpenExisting(mutexName,
MutexRights.ReadPermissions | MutexRights.ChangePermissions);
// Get the current ACL. This requires
// MutexRights.ReadPermissions.
MutexSecurity mSec = m.GetAccessControl();
string user = Environment.UserDomainName + "\\"
+ Environment.UserName;
// First, the rule that denied the current user
// the right to enter and release the mutex must
// be removed.
MutexAccessRule rule = new MutexAccessRule(user,
MutexRights.Synchronize | MutexRights.Modify,
AccessControlType.Deny);
mSec.RemoveAccessRule(rule);
// Now grant the user the correct rights.
//
rule = new MutexAccessRule(user,
MutexRights.Synchronize | MutexRights.Modify,
AccessControlType.Allow);
mSec.AddAccessRule(rule);
// Update the ACL. This requires
// MutexRights.ChangePermissions.
m.SetAccessControl(mSec);
Console.WriteLine("Updated mutex security.");
// Open the mutex with (MutexRights.Synchronize
// | MutexRights.Modify), the rights required to
// enter and release the mutex.
//
m = Mutex.OpenExisting(mutexName);
}
catch(UnauthorizedAccessException ex)
{
Console.WriteLine("Unable to change permissions: {0}",
ex.Message);
return;
}
}
// If this program created the mutex, it already owns
// the mutex.
//
if (!mutexWasCreated)
{
// Enter the mutex, and hold it until the program
// exits.
//
try
{
Console.WriteLine("Wait for the mutex.");
m.WaitOne();
Console.WriteLine("Entered the mutex.");
}
catch(UnauthorizedAccessException ex)
{
Console.WriteLine("Unauthorized access: {0}", ex.Message);
}
}
Console.WriteLine("Press the Enter key to exit.");
Console.ReadLine();
m.ReleaseMutex();
m.Dispose();
}
}
Imports System.Threading
Imports System.Security.AccessControl
Friend Class Example
<MTAThread> _
Friend Shared Sub Main()
Const mutexName As String = "MutexExample4"
Dim m As Mutex = Nothing
Dim doesNotExist as Boolean = False
Dim unauthorized As Boolean = False
' The value of this variable is set by the mutex
' constructor. It is True if the named system mutex was
' created, and False if the named mutex already existed.
'
Dim mutexWasCreated As Boolean
' Attempt to open the named mutex.
Try
' Open the mutex with (MutexRights.Synchronize Or
' MutexRights.Modify), to enter and release the
' named mutex.
'
m = Mutex.OpenExisting(mutexName)
Catch ex As WaitHandleCannotBeOpenedException
Console.WriteLine("Mutex does not exist.")
doesNotExist = True
Catch ex As UnauthorizedAccessException
Console.WriteLine("Unauthorized access: {0}", ex.Message)
unauthorized = True
End Try
' There are three cases: (1) The mutex does not exist.
' (2) The mutex exists, but the current user doesn't
' have access. (3) The mutex exists and the user has
' access.
'
If doesNotExist Then
' The mutex does not exist, so create it.
' Create an access control list (ACL) that denies the
' current user the right to enter or release the
' mutex, but allows the right to read and change
' security information for the mutex.
'
Dim user As String = Environment.UserDomainName _
& "\" & Environment.UserName
Dim mSec As New MutexSecurity()
Dim rule As New MutexAccessRule(user, _
MutexRights.Synchronize Or MutexRights.Modify, _
AccessControlType.Deny)
mSec.AddAccessRule(rule)
rule = New MutexAccessRule(user, _
MutexRights.ReadPermissions Or _
MutexRights.ChangePermissions, _
AccessControlType.Allow)
mSec.AddAccessRule(rule)
' Create a Mutex object that represents the system
' mutex named by the constant 'mutexName', with
' initial ownership for this thread, and with the
' specified security access. The Boolean value that
' indicates creation of the underlying system object
' is placed in mutexWasCreated.
'
m = New Mutex(True, mutexName, mutexWasCreated, mSec)
' If the named system mutex was created, it can be
' used by the current instance of this program, even
' though the current user is denied access. The current
' program owns the mutex. Otherwise, exit the program.
'
If mutexWasCreated Then
Console.WriteLine("Created the mutex.")
Else
Console.WriteLine("Unable to create the mutex.")
Return
End If
ElseIf unauthorized Then
' Open the mutex to read and change the access control
' security. The access control security defined above
' allows the current user to do this.
'
Try
m = Mutex.OpenExisting(mutexName, _
MutexRights.ReadPermissions Or _
MutexRights.ChangePermissions)
' Get the current ACL. This requires
' MutexRights.ReadPermissions.
Dim mSec As MutexSecurity = m.GetAccessControl()
Dim user As String = Environment.UserDomainName _
& "\" & Environment.UserName
' First, the rule that denied the current user
' the right to enter and release the mutex must
' be removed.
Dim rule As New MutexAccessRule(user, _
MutexRights.Synchronize Or MutexRights.Modify, _
AccessControlType.Deny)
mSec.RemoveAccessRule(rule)
' Now grant the user the correct rights.
'
rule = New MutexAccessRule(user, _
MutexRights.Synchronize Or MutexRights.Modify, _
AccessControlType.Allow)
mSec.AddAccessRule(rule)
' Update the ACL. This requires
' MutexRights.ChangePermissions.
m.SetAccessControl(mSec)
Console.WriteLine("Updated mutex security.")
' Open the mutex with (MutexRights.Synchronize
' Or MutexRights.Modify), the rights required to
' enter and release the mutex.
'
m = Mutex.OpenExisting(mutexName)
Catch ex As UnauthorizedAccessException
Console.WriteLine("Unable to change permissions: {0}", _
ex.Message)
Return
End Try
End If
' If this program created the mutex, it already owns
' the mutex.
'
If Not mutexWasCreated Then
' Enter the mutex, and hold it until the program
' exits.
'
Try
Console.WriteLine("Wait for the mutex.")
m.WaitOne()
Console.WriteLine("Entered the mutex.")
Catch ex As UnauthorizedAccessException
Console.WriteLine("Unauthorized access: {0}", _
ex.Message)
End Try
End If
Console.WriteLine("Press the Enter key to exit.")
Console.ReadLine()
m.ReleaseMutex()
m.Dispose()
End Sub
End Class
注解
name
可以是前缀Global\``Local\
,也可以指定命名空间。 Global
指定命名空间时,同步对象可以与系统上的任何进程共享。 Local
指定命名空间时,该命名空间也是未指定命名空间时的默认值,同步对象可以与同一会话中的进程共享。 在Windows,会话是登录会话,服务通常在不同的非交互式会话中运行。 在类似 Unix 的操作系统上,每个 shell 都有其自己的会话。 会话本地同步对象可能适合在进程与父/子关系之间同步,它们都在同一会话中运行。 有关Windows上的同步对象名称的详细信息,请参阅对象名称。
如果提供了请求 name
类型的同步对象并且请求的同步对象已存在于命名空间中,则使用现有同步对象。 如果命名空间中已存在不同类型的同步对象,则会引发一个 WaitHandleCannotBeOpenedException
。 否则,将创建一个新的同步对象。
如果name
不是null
且initiallyOwned
不是true
,则调用线程仅在createdNew``true
调用后拥有命名互斥体。 否则,线程可以通过调用 WaitOne 该方法来请求互斥体。
使用此构造函数在创建命名系统互斥体时将访问控制安全性应用于命名系统互斥体,从而阻止其他代码控制互斥体。
此构造函数初始化表示 Mutex 命名系统互斥体的对象。 可以创建表示同一命名系统互斥体的多个 Mutex 对象。
如果命名系统互斥体不存在,则会使用指定的访问控制安全性创建它。 如果存在命名互斥体,则忽略指定的访问控制安全性。
备注
即使拒绝或未能向当前用户授予某些访问权限,调用方也完全控制新创建 Mutex 的对象 mutexSecurity
。 但是,如果当前用户尝试获取另一个Mutex对象来表示同一命名互斥体,请使用构造函数或OpenExisting方法,Windows访问控制安全性。
如果已使用访问控制安全性创建了命名互斥体,并且调用方没有 MutexRights.FullControl,则会引发异常。 若要打开仅具有同步线程活动所需的权限的现有命名互斥体,请参阅该方法 OpenExisting 。
如果指定 null
或为 name
空字符串,则会创建本地互斥体,就像调用 Mutex(Boolean) 构造函数一样。 在这种情况下, createdNew
始终 true
为 .
由于它们是系统范围的命名互斥体,因此可用于协调跨进程边界的资源使用。
备注
在运行终端服务的服务器上,命名的系统互斥体可以具有两个级别的可见性。 如果名称以前缀“Global\”开头,则互斥体在所有终端服务器会话中可见。 如果名称以前缀“Local\”开头,则互斥体仅在创建它的终端服务器会话中可见。 在这种情况下,服务器上其他终端服务器会话中可以存在具有相同名称的单独互斥体。 如果在创建命名互斥表达式时未指定前缀,则它采用前缀“Local\”。 在终端服务器会话中,名称仅与其前缀不同的两个互斥体是单独的互斥体,并且两者都对终端服务器会话中的所有进程可见。 也就是说,前缀名称“Global\”和“Local\”描述互斥名称相对于终端服务器会话的范围,而不是相对于进程。
反斜杠 (\) 是互斥体名称中的保留字符。 请勿在互斥体名称中使用反斜杠 (\),除非在终端服务器会话中使用互斥体的注释中另有规定。 否则,即使互斥体的名称表示现有文件,也可能引发 DirectoryNotFoundException。