Một mutex là một khái niệm lập trình thường được sử dụng để giải quyết các vấn đề đa luồng. Câu hỏi của tôi với cộng đồng:
Một mutex là gì và làm thế nào để bạn sử dụng nó?
Một mutex là một khái niệm lập trình thường được sử dụng để giải quyết các vấn đề đa luồng. Câu hỏi của tôi với cộng đồng:
Một mutex là gì và làm thế nào để bạn sử dụng nó?
Câu trả lời:
Khi tôi đang có một cuộc thảo luận sôi nổi tại nơi làm việc, tôi sử dụng một con gà cao su mà tôi giữ trong bàn làm việc cho những dịp như vậy. Người cầm gà là người duy nhất được phép nói chuyện. Nếu bạn không giữ gà, bạn không thể nói. Bạn chỉ có thể chỉ ra rằng bạn muốn gà và đợi cho đến khi bạn nhận được nó trước khi bạn nói. Sau khi nói xong, bạn có thể trao lại con gà cho người điều hành, người sẽ đưa nó cho người tiếp theo nói. Điều này đảm bảo rằng mọi người không nói chuyện với nhau và cũng có không gian riêng để nói chuyện.
Thay thế Gà bằng Mutex và người bằng chỉ và về cơ bản bạn có khái niệm về một mutex.
Tất nhiên, không có thứ gọi là mutex cao su. Chỉ gà cao su. Mèo của tôi đã từng có một con chuột cao su, nhưng chúng đã ăn nó.
Tất nhiên, trước khi bạn sử dụng gà cao su, bạn cần tự hỏi mình có thực sự cần 5 người trong một phòng không và sẽ không dễ dàng hơn khi một người trong phòng tự mình làm tất cả công việc. Trên thực tế, đây chỉ là mở rộng sự tương tự, nhưng bạn có ý tưởng.
Mutex là một lá cờ loại trừ lẫn nhau. Nó hoạt động như một người giữ cổng cho một phần mã cho phép một luồng vào và chặn truy cập đến tất cả các luồng khác. Điều này đảm bảo rằng mã được kiểm soát sẽ chỉ bị tấn công bởi một luồng duy nhất tại một thời điểm. Chỉ cần chắc chắn để phát hành mutex khi bạn đã hoàn tất. :)
Loại trừ lẫn nhau. Đây là mục Wikipedia trên đó:
http://en.wikipedia.org/wiki/Mutual_exinating
Điểm của một mutex là đồng bộ hóa hai luồng. Khi bạn có hai luồng cố gắng truy cập vào một tài nguyên, mẫu chung là có khối mã đầu tiên cố gắng truy cập để đặt mutex trước khi nhập mã. Khi khối mã thứ hai thử truy cập, nó sẽ thấy mutex được đặt và đợi cho đến khi khối mã đầu tiên hoàn thành (và hủy đặt mutex), sau đó tiếp tục.
Chi tiết cụ thể về cách thực hiện điều này rõ ràng rất khác nhau bởi ngôn ngữ lập trình.
Khi bạn có một ứng dụng đa luồng, các luồng khác nhau đôi khi chia sẻ một tài nguyên chung, chẳng hạn như một biến hoặc tương tự. Nguồn chia sẻ này thường không thể được truy cập cùng một lúc, do đó, một cấu trúc là cần thiết để đảm bảo rằng chỉ có một luồng đang sử dụng tài nguyên đó tại một thời điểm.
Khái niệm này được gọi là "loại trừ lẫn nhau" (Mutex ngắn) và là một cách để đảm bảo rằng chỉ có một luồng được cho phép trong khu vực đó, sử dụng tài nguyên đó, v.v.
Cách sử dụng chúng là ngôn ngữ cụ thể, nhưng thường (nếu không luôn luôn) dựa trên một mutex hệ điều hành.
Một số ngôn ngữ không cần cấu trúc này, do mô hình, ví dụ lập trình chức năng (Haskell, ML là những ví dụ điển hình).
Trong C #, mutex phổ biến được sử dụng là Monitor . Loại này là ' System.Threading.Monitor '. Nó cũng có thể được sử dụng ngầm thông qua câu lệnh ' khóa (Đối tượng) '. Một ví dụ về việc sử dụng nó là khi xây dựng một lớp Singleton.
private static readonly Object instanceLock = new Object();
private static MySingleton instance;
public static MySingleton Instance
{
lock(instanceLock)
{
if(instance == null)
{
instance = new MySingleton();
}
return instance;
}
}
Câu lệnh khóa sử dụng đối tượng khóa riêng tạo ra một phần quan trọng. Yêu cầu mỗi luồng để đợi cho đến khi kết thúc trước đó. Chuỗi đầu tiên sẽ nhập phần và khởi tạo thể hiện. Chuỗi thứ hai sẽ chờ, vào phần và lấy ví dụ khởi tạo.
Bất kỳ loại đồng bộ hóa nào của thành viên tĩnh đều có thể sử dụng câu lệnh khóa tương tự.
A là gì Mutex ?
Mutex (Trên thực tế, thuật ngữ mutex là viết tắt của loại trừ lẫn nhau) còn được gọi là spinlock là công cụ đồng bộ hóa đơn giản nhất được sử dụng để bảo vệ các khu vực quan trọng và do đó ngăn chặn các điều kiện chủng tộc. Đó là một luồng phải có được khóa trước khi vào phần quan trọng (Trong phần quan trọng, nhiều luồng chia sẻ một biến chung, cập nhật bảng, viết tệp, v.v.), nó giải phóng khóa khi rời khỏi phần quan trọng.
Điều kiện cuộc đua là gì?
Một điều kiện cuộc đua xảy ra khi hai hoặc nhiều luồng có thể truy cập dữ liệu được chia sẻ và họ cố gắng thay đổi nó cùng một lúc. Vì thuật toán lập lịch luồng có thể trao đổi giữa các luồng bất cứ lúc nào, bạn không biết thứ tự các luồng sẽ cố gắng truy cập dữ liệu được chia sẻ. Do đó, kết quả của sự thay đổi dữ liệu phụ thuộc vào thuật toán lập lịch luồng, tức là cả hai luồng đều "chạy đua" để truy cập / thay đổi dữ liệu.
Ví dụ thực tế:
Khi tôi đang có một cuộc thảo luận sôi nổi tại nơi làm việc, tôi sử dụng một con gà cao su mà tôi giữ trong bàn làm việc cho những dịp như vậy. Người cầm gà là người duy nhất được phép nói chuyện. Nếu bạn không giữ gà, bạn không thể nói. Bạn chỉ có thể chỉ ra rằng bạn muốn gà và đợi cho đến khi bạn nhận được nó trước khi bạn nói. Sau khi nói xong, bạn có thể trao lại con gà cho người điều hành, người sẽ đưa nó cho người tiếp theo nói. Điều này đảm bảo rằng mọi người không nói chuyện với nhau và cũng có không gian riêng để nói chuyện.
Thay thế Gà bằng Mutex và người bằng chỉ và về cơ bản bạn có khái niệm về một mutex.
@Xetius
Cách sử dụng trong C #:
Ví dụ này cho thấy cách một đối tượng Mutex cục bộ được sử dụng để đồng bộ hóa quyền truy cập vào tài nguyên được bảo vệ. Bởi vì mỗi luồng gọi bị chặn cho đến khi nó có được quyền sở hữu của mutex, nên nó phải gọi phương thức ReleaseMutex để giải phóng quyền sở hữu của luồng.
using System;
using System.Threading;
class Example
{
// 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 newThread = new Thread(new ThreadStart(ThreadProc));
newThread.Name = String.Format("Thread{0}", i + 1);
newThread.Start();
}
// The main thread exits, but the application continues to
// run until all foreground threads have exited.
}
private static void ThreadProc()
{
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.
Console.WriteLine("{0} is requesting the mutex",
Thread.CurrentThread.Name);
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",
Thread.CurrentThread.Name);
// Release the Mutex.
mut.ReleaseMutex();
Console.WriteLine("{0} has released the mutex",
Thread.CurrentThread.Name);
}
}
// The example displays output like the following:
// Thread1 is requesting the mutex
// Thread2 is requesting the mutex
// Thread1 has entered the protected area
// Thread3 is requesting the mutex
// Thread1 is leaving the protected area
// Thread1 has released the mutex
// Thread3 has entered the protected area
// Thread3 is leaving the protected area
// Thread3 has released the mutex
// Thread2 has entered the protected area
// Thread2 is leaving the protected area
// Thread2 has released the mutex
Có một số câu trả lời tuyệt vời ở đây, đây là một sự tương tự tuyệt vời khác để giải thích mutex là gì :
Hãy xem xét nhà vệ sinh đơn với một chìa khóa . Khi ai đó đi vào, họ lấy chìa khóa và nhà vệ sinh bị chiếm dụng . Nếu người khác cần sử dụng nhà vệ sinh, họ cần phải đợi trong hàng đợi . Khi người trong nhà vệ sinh xong , họ chuyển chìa khóa cho người tiếp theo xếp hàng. Có ý nghĩa, phải không?
Chuyển đổi nhà vệ sinh trong câu chuyện thành một tài nguyên được chia sẻ và chìa khóa cho một mutex . Lấy chìa khóa vào nhà vệ sinh (có được một khóa) cho phép bạn sử dụng nó. Nếu không có chìa khóa (khóa bị khóa), bạn phải chờ. Khi người đó trả lại chìa khóa ( mở khóa ), bạn có thể lấy nó ngay bây giờ.
Để hiểu MUTEX lúc đầu, bạn cần biết "điều kiện cuộc đua" là gì và sau đó chỉ có bạn mới hiểu tại sao MUTEX lại cần thiết. Giả sử bạn có một chương trình đa luồng và bạn có hai luồng. Bây giờ, bạn có một công việc trong hàng đợi công việc. Chuỗi đầu tiên sẽ kiểm tra hàng đợi công việc và sau khi tìm thấy công việc, nó sẽ bắt đầu thực hiện nó. Chuỗi thứ hai cũng sẽ kiểm tra hàng đợi công việc và thấy rằng có một công việc trong hàng đợi. Vì vậy, nó cũng sẽ gán con trỏ công việc tương tự. Vì vậy, bây giờ những gì xảy ra, cả hai luồng đang thực hiện cùng một công việc. Điều này sẽ gây ra một lỗi phân khúc. Đây là ví dụ về một điều kiện cuộc đua.
Giải pháp cho vấn đề này là MUTEX. MUTEX là một loại khóa khóa một luồng tại một thời điểm. Nếu một luồng khác muốn khóa nó, thì luồng chỉ bị chặn.
Mutexes rất hữu ích trong các trường hợp bạn cần thực thi quyền truy cập độc quyền vào tài nguyên trên nhiều quy trình, trong đó khóa thông thường sẽ không giúp ích vì nó chỉ hoạt động trên các luồng.
Mutex: Mutex là viết tắt của Mut ual Ex clusion. Nó có nghĩa là tại một thời điểm một quá trình / chủ đề có thể nhập vào phần quan trọng. Trong lập trình đồng thời trong đó nhiều luồng / tiến trình cố gắng cập nhật tài nguyên được chia sẻ (bất kỳ biến nào, bộ nhớ dùng chung, v.v.) có thể dẫn đến một số kết quả không mong muốn. (Vì kết quả phụ thuộc vào luồng / tiến trình nào có quyền truy cập đầu tiên).
Để tránh kết quả không mong muốn như vậy, chúng tôi cần một số cơ chế đồng bộ hóa, đảm bảo rằng chỉ có một luồng / quy trình được truy cập vào tài nguyên như vậy tại một thời điểm.
thư viện pthread cung cấp hỗ trợ cho Mutex.
typedef union
{
struct __pthread_mutex_s
{
***int __lock;***
unsigned int __count;
int __owner;
#ifdef __x86_64__
unsigned int __nusers;
#endif
int __kind;
#ifdef __x86_64__
short __spins;
short __elision;
__pthread_list_t __list;
# define __PTHREAD_MUTEX_HAVE_PREV 1
# define __PTHREAD_SPINS 0, 0
#else
unsigned int __nusers;
__extension__ union
{
struct
{
short __espins;
short __elision;
# define __spins __elision_data.__espins
# define __elision __elision_data.__elision
# define __PTHREAD_SPINS { 0, 0 }
} __elision_data;
__pthread_slist_t __list;
};
#endif
Đây là cấu trúc cho kiểu dữ liệu mutex tức là pthread_mutex_t. Khi mutex bị khóa, __lock được đặt thành 1. Khi nó được mở khóa __lock được đặt thành 0.
Điều này đảm bảo rằng không có hai tiến trình / luồng có thể truy cập vào phần quan trọng cùng một lúc.