Một mutex là gì?


654

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ó?


2
Đây là một bài viết hay về sự khác biệt: barrgroup.com/Embedded-Systems/How-To/RTOS-Mutex-Semaphore
Adam Davis

Hướng dẫn về mutex có thể giúp dọn dẹp mọi thứ: stackoverflow.com/questions/4989451/mutex-example-tutorial
Nav

1
Một mutex giống như chìa khóa phòng tắm tại trạm xăng, đảm bảo rằng chỉ một người có thể sử dụng phòng tắm tại một thời điểm VÀ không ai khác có thể sử dụng nhà vệ sinh cho đến khi người thuê hiện tại kết thúc và trả lại chìa khóa.
jonschlinkert

Câu trả lời:


2153

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.


9
Câu trả lời chính xác. Có thể tranh luận rằng Mutex thực sự là quy tắc ngăn chặn con gà được thông qua? và con gà là thứ bạn đang khóa?
SirYakalot

3
@SirYakalot, ý bạn là gà là tài nguyên, còn người điều hành là mutex?
Owen

156
Con gà là mutex . Người ta dựng lên mu .. gà là chủ đề cạnh tranh . Người điều hành là HĐH . Khi mọi người yêu cầu gà, họ làm một yêu cầu khóa. Khi bạn gọi mutex.lock (), luồng của bạn sẽ bị khóa () và đưa ra yêu cầu khóa đối với HĐH. Khi HĐH phát hiện ra rằng mutex đã được giải phóng khỏi một luồng, nó chỉ đưa nó cho bạn và khóa () trả về - mutex giờ là của bạn và chỉ của bạn. Không ai khác có thể đánh cắp nó, bởi vì gọi khóa () sẽ chặn anh ta. Ngoài ra còn có try_lock () sẽ chặn và trả về true khi mutex là của bạn và ngay lập tức sai nếu mutex được sử dụng.
Петър Петров

4
Bạn là một thiên tài. Bạn có thể sử dụng phép ẩn dụ gà cao su để giải thích màn hình không?
Riccardo

98
Đôi khi nguồn gốc của một số khái niệm lập trình là không rõ ràng. Một người mới có thể đi xung quanh tự hỏi tại sao mọi người đang nói về regex. Không rõ ràng rằng regex là viết tắt của [reg] ular [ex] pression. Tương tự, mutex là viết tắt của clusion [mut] ual [ex]. Điều này có thể làm cho ý nghĩa của thuật ngữ dễ tiêu hóa hơn. @TheSmurf liên kết với nó trong câu trả lời của họ, nhưng có thể tốt để thêm nó ở đây cho mục đích lịch sử.
Dodzi Dzakuma

137

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. :)


10
Một mutex không có gì để làm với một phần mã mỗi se, nó bảo vệ một số tài nguyên. Tài nguyên đó có thể là một đoạn mã nếu mutex chỉ được sử dụng xung quanh mã đó, nhưng ngay khi bạn bắt đầu sử dụng mutex ở nhiều nơi trong mã của bạn, thì lời giải thích của bạn không thành công. Thông thường, nó cũng có thể được sử dụng để bảo vệ một số cấu trúc dữ liệu, có thể được truy cập từ nhiều nơi trong mã.
paxdiablo

72

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.


65

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).


26

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ự.


1
Đây là một câu trả lời phụ thuộc thực hiện. Ngoài ra, trong CS một màn hình khác với mutex. Màn hình có một cơ chế đồng bộ hóa nhưng mutex chỉ khóa điều đó cho đến khi không còn cần thiết. IDK về chi tiết triển khai hoặc ngữ nghĩa C #, nhưng tôi nghĩ bối cảnh của câu hỏi rộng hơn
marcoslhc

25

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

Mutex tham chiếu MSDN


1
một ví dụ rất hay
Siwei Shen

22

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ẻ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ờ.


Nhưng ví dụ c # không hỗ trợ xác nhận hàng đợi của bạn, "chuyển khóa cho người tiếp theo trong hàng đợi". Ví dụ này cho thấy một ngăn xếp hoặc ngẫu nhiên. 1, 2, & 3 tất cả yêu cầu truy cập, theo trình tự đó. Một được cho phép đầu tiên vào khu vực được bảo vệ, và sau đó ba được phép. Một hàng đợi sẽ đưa nó đến lần thứ hai.
donvnielsen

Tôi đã không đề cập đến bất kỳ triển khai cụ thể, hoặc ngôn ngữ lập trình cụ thể. Ví dụ của tôi liên quan đến sự trừu tượng hóa mức độ cao của mutex như một nguyên tắc.
Chen A.

18

Để 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.

Chủ đề MUTEX trong liên kết tệp pdf này thực sự đáng đọc.


Theo "chủ đề MUTEX", bạn có nghĩa là phần về semaphores, bởi vì các ví dụ của nó là semaphores, phải không?
Carl G

2
một Mutex chỉ là một semaphore có giá trị 1
marcoslhc

Tên của cuốn sách của chương đó bạn đã chia sẻ là gì? Xin vui lòng
Omar Faroque Anik

@OmarFaroqueAnik cuốn sách được tham chiếu là Lập trình Linux nâng cao của CodeSourcery LLC, được xuất bản bởi New Riders Publishing và có thể được truy cập từ trang chủ của tên miền được liên kết.
RMart

11

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.


Điều đó có thực sự đúng không? Các quy trình riêng lẻ sẽ tạo bản sao mutex của riêng họ?
Leon

0

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.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.