Saya ingin memastikan ini ada di luar sana, karena sangat sulit untuk memperbaikinya:
using System.Runtime.InteropServices; //GuidAttribute
using System.Reflection; //Assembly
using System.Threading; //Mutex
using System.Security.AccessControl; //MutexAccessRule
using System.Security.Principal; //SecurityIdentifier
static void Main(string[] args)
{
// get application GUID as defined in AssemblyInfo.cs
string appGuid =
((GuidAttribute)Assembly.GetExecutingAssembly().
GetCustomAttributes(typeof(GuidAttribute), false).
GetValue(0)).Value.ToString();
// unique id for global mutex - Global prefix means it is global to the machine
string mutexId = string.Format( "Global\\{{{0}}}", appGuid );
// Need a place to store a return value in Mutex() constructor call
bool createdNew;
// edited by Jeremy Wiebe to add example of setting up security for multi-user usage
// edited by 'Marc' to work also on localized systems (don't use just "Everyone")
var allowEveryoneRule =
new MutexAccessRule( new SecurityIdentifier( WellKnownSidType.WorldSid
, null)
, MutexRights.FullControl
, AccessControlType.Allow
);
var securitySettings = new MutexSecurity();
securitySettings.AddAccessRule(allowEveryoneRule);
// edited by MasonGZhwiti to prevent race condition on security settings via VanNguyen
using (var mutex = new Mutex(false, mutexId, out createdNew, securitySettings))
{
// edited by acidzombie24
var hasHandle = false;
try
{
try
{
// note, you may want to time out here instead of waiting forever
// edited by acidzombie24
// mutex.WaitOne(Timeout.Infinite, false);
hasHandle = mutex.WaitOne(5000, false);
if (hasHandle == false)
throw new TimeoutException("Timeout waiting for exclusive access");
}
catch (AbandonedMutexException)
{
// Log the fact that the mutex was abandoned in another process,
// it will still get acquired
hasHandle = true;
}
// Perform your work here.
}
finally
{
// edited by acidzombie24, added if statement
if(hasHandle)
mutex.ReleaseMutex();
}
}
}
using
untuk memeriksacreatedNew
dan menambahkanmutex.Dispose()
di dalamfinally
. Saya tidak dapat menjelaskannya dengan jelas (saya tidak tahu alasannya) saat ini tetapi saya sendiri mengalami situasi ketikamutex.WaitOne
kembalitrue
setelahcreatedNew
menjadifalse
(saya memperoleh mutex di arusAppDomain
dan kemudian memuat yang baruAppDomain
dan mengeksekusi kode yang sama dari didalamnya).exitContext = false
melakukan sesuatumutex.WaitOne(5000, false)
? Kelihatannya seperti itu hanya bisa menyebabkan menegaskan di CoreCLR , 2. Jika siapa pun bertanya-tanya, diMutex
's konstruktor, alasan mengapainitiallyOwned
adalahfalse
sebagian dijelaskan oleh artikel MSDN ini .Menggunakan jawaban yang diterima saya membuat kelas penolong sehingga Anda bisa menggunakannya dengan cara yang sama Anda akan menggunakan pernyataan Lock. Saya pikir saya akan berbagi.
Menggunakan:
Dan kelas pembantu:
sumber
< 0
daripada<= 0
._mutex.Close()
alih-alih_mutex.Dispose()
dalam metode Buang bekerja untuk saya. Kesalahan itu disebabkan oleh mencoba untuk membuang WaitHandle yang mendasarinya.Mutex.Close()
membuang sumber daya yang mendasarinya.Ada kondisi ras dalam jawaban yang diterima ketika 2 proses berjalan di bawah 2 pengguna yang berbeda yang mencoba menginisialisasi mutex pada saat yang sama. Setelah proses pertama menginisialisasi mutex, jika proses kedua mencoba untuk menginisialisasi mutex sebelum proses pertama menetapkan aturan akses untuk semua orang, pengecualian yang tidak sah akan dilemparkan oleh proses kedua.
Lihat di bawah untuk jawaban yang benar:
sumber
Contoh ini akan keluar setelah 5 detik jika instance lain sudah berjalan.
sumber
Baik Mutex maupun WinApi CreateMutex () tidak berfungsi untuk saya.
Solusi alternatif:
Dan
SingleApplicationDetector
:Alasan menggunakan Semaphore, bukan Mutex:
Ref: Semaphore.OpenExisting ()
sumber
Semaphore.OpenExisting
dannew Semaphore
.Terkadang belajar dengan memberi contoh sangat membantu. Jalankan aplikasi konsol ini di tiga jendela konsol yang berbeda. Anda akan melihat bahwa aplikasi yang Anda jalankan pertama mendapatkan mutex terlebih dahulu, sementara dua lainnya menunggu giliran. Kemudian tekan enter di aplikasi pertama, Anda akan melihat bahwa aplikasi 2 sekarang terus berjalan dengan memperoleh mutex, namun aplikasi 3 sedang menunggu giliran. Setelah Anda menekan enter dalam aplikasi 2 Anda akan melihat bahwa aplikasi 3 berlanjut. Ini menggambarkan konsep mutex yang melindungi bagian kode yang akan dieksekusi hanya oleh satu utas (dalam hal ini proses) seperti menulis ke file sebagai contoh.
sumber
Mutex global tidak hanya memastikan memiliki hanya satu instance aplikasi. Saya pribadi lebih suka menggunakan Microsoft.VisualBasic untuk memastikan aplikasi instance tunggal seperti dijelaskan dalam Apa cara yang benar untuk membuat aplikasi WPF instance tunggal? (Jawaban Dale Ragan) ... Saya menemukan bahwa lebih mudah untuk menyampaikan argumen yang diterima pada startup aplikasi baru ke aplikasi instance tunggal awal.
Tetapi mengenai beberapa kode sebelumnya di utas ini, saya lebih suka untuk tidak membuat Mutex setiap kali saya ingin memiliki kunci di dalamnya. Itu bisa saja baik untuk aplikasi contoh tunggal tetapi dalam penggunaan lain tampaknya bagi saya telah berlebihan.
Itu sebabnya saya menyarankan implementasi ini sebagai gantinya:
Pemakaian:
Mutex Global Wrapper:
Pelayan
sumber
Solusi (untuk WPF) tanpa WaitOne karena dapat menyebabkan AbandonedMutexException. Solusi ini menggunakan konstruktor Mutex yang mengembalikan boolean CreatedNew untuk memeriksa apakah mutex sudah dibuat. Itu juga menggunakan GetType (). GUID jadi mengubah nama sebuah executable tidak memungkinkan beberapa instance.
Global vs mutex lokal lihat catatan di: https://docs.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=netframework-4.8
Karena Mutex mengimplementasikan IDisposable, itu dirilis secara otomatis tetapi untuk panggilan kelengkapan, buang:
Pindahkan semuanya ke kelas dasar dan tambahkan allowEveryoneRule dari jawaban yang diterima. Juga menambahkan ReleaseMutex meskipun sepertinya tidak benar-benar diperlukan karena dirilis secara otomatis oleh OS (bagaimana jika aplikasi crash dan tidak pernah memanggil ReleaseMutex, Anda perlu reboot?).
sumber