Có sự khác biệt nào giữa một semaphore nhị phân và mutex hay về cơ bản chúng giống nhau không?
Có sự khác biệt nào giữa một semaphore nhị phân và mutex hay về cơ bản chúng giống nhau không?
Câu trả lời:
Họ KHÔNG phải là điều tương tự. Chúng được sử dụng cho các mục đích khác nhau!
Mặc dù cả hai loại semaphores đều có trạng thái đầy đủ / trống và sử dụng cùng một API, cách sử dụng của chúng rất khác nhau.
Các ngữ nghĩa loại trừ lẫn nhau Các ngữ nghĩa loại trừ
lẫn nhau được sử dụng để bảo vệ các tài nguyên được chia sẻ (cấu trúc dữ liệu, tệp, v.v.).
Một semaphore Mutex được "sở hữu" bởi nhiệm vụ đảm nhận nó. Nếu Nhiệm vụ B cố gắng semGive một mutex hiện đang được thực hiện bởi Nhiệm vụ A, cuộc gọi của Nhiệm vụ B sẽ trả về lỗi và không thành công.
Mutexes luôn sử dụng trình tự sau:
- Bán kết - Phần quan trọng - SemGive
Đây là một ví dụ đơn giản:
Chủ đề A Chủ đề B Lấy Mutex tiếp cận thông tin ... Lấy Mutex <== Sẽ chặn ... Cung cấp dữ liệu truy cập Mutex <== Unblocks ... Tặng Mutex
Semaphore
nhị phân nhị phân Semaphore giải quyết một câu hỏi hoàn toàn khác nhau:
Task A Task B
... Take BinSemaphore <== wait for something
Do Something Noteworthy
Give BinSemaphore do something <== unblocks
Lưu ý rằng với một semaphore nhị phân, B có thể lấy semaphore và A để cung cấp cho nó.
Một lần nữa, một semaphore nhị phân KHÔNG bảo vệ tài nguyên khỏi sự truy cập. Hành động cho và nhận một semaphore về cơ bản được tách rời.
Nó thường không có ý nghĩa đối với cùng một nhiệm vụ để đưa ra và thực hiện trên cùng một semaphore nhị phân.
vì vậy semaphores phù hợp hơn cho một số vấn đề đồng bộ hóa như nhà sản xuất-người tiêu dùng.
Trên Windows, semaphores nhị phân giống như các đối tượng sự kiện hơn là mutexes.
Mutex can be released only by thread that had acquired it
- Tôi vừa thử với một chương trình dựa trên pthread_mutex đơn giản, một luồng có thể mở khóa mutex bị khóa trong luồng chính
Ví dụ về Nhà vệ sinh là một sự tương tự thú vị:
Đột biến:
Là một chìa khóa cho một nhà vệ sinh. Một người có thể có chìa khóa - chiếm nhà vệ sinh - tại thời điểm đó. Khi kết thúc, người này đưa (giải phóng) chìa khóa cho người tiếp theo trong hàng đợi.
Chính thức: "Mutex thường được sử dụng để tuần tự hóa quyền truy cập vào một phần của mã được cấp lại mà không thể được thực thi đồng thời bởi nhiều hơn một luồng. Một đối tượng mutex chỉ cho phép một luồng vào một phần được kiểm soát, buộc các luồng khác cố gắng truy cập vào phần đó để đợi cho đến khi luồng đầu tiên thoát khỏi phần đó. " Tham chiếu: Thư viện nhà phát triển Symbian
(Một mutex thực sự là một semaphore có giá trị 1.)
Semaphore:
Là số lượng chìa khóa nhà vệ sinh giống hệt miễn phí. Ví dụ, giả sử chúng ta có bốn nhà vệ sinh với ổ khóa và chìa khóa giống hệt nhau. Số lượng semaphore - số lượng khóa - được đặt thành 4 ở đầu (tất cả bốn nhà vệ sinh đều miễn phí), sau đó giá trị đếm sẽ giảm khi mọi người đến. Nếu tất cả các nhà vệ sinh đều đầy, tức là. không còn khóa miễn phí, số lượng semaphore là 0. Bây giờ, khi eq. một người rời khỏi nhà vệ sinh, semaphore được tăng lên 1 (một khóa miễn phí) và được trao cho người tiếp theo trong hàng đợi.
Chính thức: "Một semaphore hạn chế số lượng người dùng đồng thời của một tài nguyên được chia sẻ lên đến một số lượng tối đa. Chủ đề có thể yêu cầu quyền truy cập vào tài nguyên (giảm semaphore) và có thể báo hiệu rằng họ đã sử dụng tài nguyên (tăng semaphore). " Tham chiếu: Thư viện nhà phát triển Symbian
Những bài viết hay về chủ đề này:
Từ phần 2:
Mutex tương tự như các nguyên tắc của semaphore nhị phân với một điểm khác biệt đáng kể: nguyên tắc sở hữu. Quyền sở hữu là khái niệm đơn giản mà khi một tác vụ khóa (mua lại) một mutex chỉ có nó mới có thể mở khóa (phát hành) nó. Nếu một tác vụ cố gắng mở khóa một mutex mà nó không bị khóa (do đó không sở hữu) thì sẽ gặp phải một điều kiện lỗi và quan trọng nhất là mutex không được mở khóa. Nếu đối tượng loại trừ lẫn nhau không có quyền sở hữu thì không liên quan đến cái mà nó được gọi, nó không phải là một mutex.
Vì không có câu trả lời nào ở trên xóa được sự nhầm lẫn, đây là câu trả lời cho sự nhầm lẫn của tôi.
Nói đúng ra, mutex là một cơ chế khóa được sử dụng để đồng bộ hóa quyền truy cập vào tài nguyên. Chỉ một tác vụ (có thể là một luồng hoặc quá trình dựa trên sự trừu tượng hóa hệ điều hành) có thể có được mutex. Điều đó có nghĩa là sẽ có quyền sở hữu liên quan đến mutex và chỉ chủ sở hữu mới có thể phát hành khóa (mutex).
Semaphore là cơ chế báo hiệu (Tôi đã hoàn thành, bạn có thể thực hiện trên loại tín hiệu này). Ví dụ: nếu bạn đang nghe các bài hát (giả sử là một tác vụ) trên điện thoại di động của mình và đồng thời bạn của bạn gọi cho bạn, một ngắt sẽ được kích hoạt theo đó một thói quen dịch vụ ngắt (ISR) sẽ báo hiệu tác vụ xử lý cuộc gọi thức dậy .
Ngữ nghĩa đồng bộ hóa của chúng rất khác nhau:
Như vậy, người ta có thể thấy một mutex như một mã thông báo được truyền từ nhiệm vụ này sang nhiệm vụ khác và một semaphore là đèn đỏ giao thông (nó báo hiệu cho ai đó rằng nó có thể tiến hành).
Ở cấp độ lý thuyết, chúng không khác nhau về mặt ngữ nghĩa. Bạn có thể thực hiện một mutex bằng semaphores hoặc ngược lại (xem ví dụ ở đây ). Trong thực tế, việc thực hiện là khác nhau và họ cung cấp các dịch vụ hơi khác nhau.
Sự khác biệt thực tế (về các dịch vụ hệ thống xung quanh chúng) là việc triển khai một mutex nhằm mục đích trở thành một cơ chế đồng bộ hóa nhẹ hơn. Trong oracle-speak, mutexes được gọi là chốt và semaphores được gọi là chờ đợi .
Ở cấp độ thấp nhất, họ sử dụng một số loại thử nghiệm nguyên tử và cơ chế thiết lập . Điều này đọc giá trị hiện tại của một vị trí bộ nhớ, tính toán một số loại điều kiện và viết ra một giá trị tại vị trí đó trong một lệnh duy nhất không thể bị gián đoạn . Điều này có nghĩa là bạn có thể có được một mutex và kiểm tra xem có ai khác có nó trước bạn không.
Một triển khai mutex điển hình có một quy trình hoặc luồng thực hiện lệnh test-and-set và đánh giá xem có thứ gì khác đã đặt mutex không. Một điểm quan trọng ở đây là không có sự tương tác với bộ lập lịch , vì vậy chúng tôi không có ý tưởng (và không quan tâm) người đã đặt khóa. Sau đó, chúng tôi hoặc từ bỏ lát cắt thời gian của mình và thử lại khi tác vụ được lên lịch lại hoặc thực hiện khóa xoay . Khóa xoay là một thuật toán như:
Count down from 5000:
i. Execute the test-and-set instruction
ii. If the mutex is clear, we have acquired it in the previous instruction
so we can exit the loop
iii. When we get to zero, give up our time slice.
Khi chúng tôi thực hiện xong mã được bảo vệ của chúng tôi (được gọi là phần quan trọng ), chúng tôi chỉ đặt giá trị mutex thành 0 hoặc bất cứ điều gì có nghĩa là 'rõ ràng'. Nếu nhiều tác vụ đang cố gắng để có được mutex, thì tác vụ tiếp theo sẽ được lên lịch sau khi mutex được phát hành sẽ có quyền truy cập vào tài nguyên. Thông thường, bạn sẽ sử dụng mutexes để kiểm soát tài nguyên được đồng bộ hóa, nơi chỉ cần truy cập độc quyền trong khoảng thời gian rất ngắn, thông thường để thực hiện cập nhật lên cấu trúc dữ liệu được chia sẻ.
Một semaphore là một cấu trúc dữ liệu được đồng bộ hóa (thường sử dụng một mutex) có số đếm và một số trình bao bọc cuộc gọi hệ thống tương tác với bộ lập lịch ở độ sâu hơn một chút so với các thư viện mutex. Semaphores được tăng lên và giảm dần và được sử dụng để chặn các nhiệm vụ cho đến khi một cái gì đó khác đã sẵn sàng. Xem Vấn đề về Nhà sản xuất / Người tiêu dùng để biết ví dụ đơn giản về điều này. Semaphores được khởi tạo cho một số giá trị - một semaphore nhị phân chỉ là một trường hợp đặc biệt trong đó semaphore được khởi tạo thành 1. Đăng lên một semaphore có tác dụng đánh thức một quá trình chờ đợi.
Một thuật toán semaphore cơ bản trông giống như:
(somewhere in the program startup)
Initialise the semaphore to its start-up value.
Acquiring a semaphore
i. (synchronised) Attempt to decrement the semaphore value
ii. If the value would be less than zero, put the task on the tail of the list of tasks waiting on the semaphore and give up the time slice.
Posting a semaphore
i. (synchronised) Increment the semaphore value
ii. If the value is greater or equal to the amount requested in the post at the front of the queue, take that task off the queue and make it runnable.
iii. Repeat (ii) for all tasks until the posted value is exhausted or there are no more tasks waiting.
Trong trường hợp của một semaphore nhị phân, sự khác biệt thực tế chính giữa hai là bản chất của các dịch vụ hệ thống xung quanh cấu trúc dữ liệu thực tế.
EDIT: Như evan đã chỉ ra một cách đúng đắn, spinlocks sẽ làm chậm một bộ vi xử lý. Bạn sẽ chỉ sử dụng một spinlock trên hộp đa bộ xử lý vì trên một bộ xử lý duy nhất, quá trình giữ mutex sẽ không bao giờ thiết lập lại nó trong khi một tác vụ khác đang chạy. Spinlocks chỉ hữu ích trên các kiến trúc đa bộ xử lý.
futex
gọi hệ thống tồn tại để hỗ trợ độ trễ thấp userspace mutex / semaphore triển khai. en.wikipedia.org/wiki/Futex ) Trong con đường nhanh không tranh chấp, hoặc nếu tài nguyên trở nên sớm có sẵn, bạn không bao giờ có những phí của một cuộc gọi hệ thống. Nhưng bạn không dành nhiều hơn một vài giây chờ đợi bận rộn (quay). Tất nhiên, điều chỉnh các tham số của back-loop spin và chờ là phụ thuộc vào phần cứng và khối lượng công việc, nhưng thư viện tiêu chuẩn thường có các lựa chọn hợp lý.
Mặc dù mutex & semaphores được sử dụng làm nguyên thủy đồng bộ hóa, có một sự khác biệt lớn giữa chúng. Trong trường hợp của mutex, chỉ có luồng bị khóa hoặc có được mutex mới có thể mở khóa nó. Trong trường hợp của một semaphore, một luồng chờ trên một semaphore có thể được báo hiệu bởi một luồng khác. Một số hệ điều hành hỗ trợ sử dụng mutex & semaphores giữa tiến trình. Thông thường việc sử dụng là tạo ra trong bộ nhớ chia sẻ.
Mutex: Giả sử chúng ta có chủ đề phần quan trọng mà T1 muốn truy cập thì nó sẽ thực hiện theo các bước dưới đây. T1:
Semaphore nhị phân: Nó hoạt động dựa trên tín hiệu chờ đợi và tín hiệu. Wait (s) giảm giá trị "s" xuống một giá trị "s" thường được khởi tạo với giá trị "1", tín hiệu (s) tăng giá trị "s" lên một. nếu giá trị "s" là 1 nghĩa là không ai sử dụng phần quan trọng, khi giá trị bằng 0 nghĩa là phần quan trọng đang được sử dụng. giả sử luồng T2 đang sử dụng phần quan trọng thì nó sẽ thực hiện theo các bước dưới đây. T2:
Sự khác biệt chính giữa Mutex và Baph semaphore là trong Mutext nếu luồng khóa phần quan trọng thì nó phải mở khóa phần quan trọng, không có luồng nào khác có thể mở khóa nó, nhưng trong trường hợp semaphore nhị phân nếu một luồng khóa phần quan trọng sử dụng chức năng Wait (s) thì giá trị của s trở thành "0" và không ai có thể truy cập nó cho đến khi giá trị của "s" trở thành 1 nhưng giả sử một số tín hiệu gọi luồng khác thì giá trị của "s" trở thành 1 và nó cho phép chức năng khác sử dụng phần quan trọng. do đó trong chủ đề semaphore nhị phân không có quyền sở hữu.
Trên Windows, có hai điểm khác biệt giữa mutexes và semaphores:
Một mutex chỉ có thể được phát hành bởi luồng có quyền sở hữu, tức là luồng trước đây được gọi là hàm Wait, (hoặc quyền sở hữu khi tạo nó). Một semaphore có thể được phát hành bởi bất kỳ chủ đề.
Một chuỗi có thể gọi một hàm chờ liên tục trên một mutex mà không chặn. Tuy nhiên, nếu bạn gọi một hàm chờ hai lần trên một semaphore nhị phân mà không giải phóng semaphore ở giữa, thì luồng sẽ chặn.
Bạn rõ ràng sử dụng mutex để khóa dữ liệu trong một luồng được truy cập bởi một luồng khác cùng một lúc. Giả sử rằng bạn vừa gọi lock()
và đang trong quá trình truy cập dữ liệu. Điều này có nghĩa là bạn không mong đợi bất kỳ luồng nào khác (hoặc một phiên bản khác của cùng mã luồng) truy cập vào cùng một dữ liệu bị khóa bởi cùng một mutex. Đó là, nếu đó là cùng một mã luồng được thực thi trên một thể hiện luồng khác, chạm vào khóa, thìlock()
nên chặn dòng điều khiển ở đó. Điều này áp dụng cho một luồng sử dụng một mã luồng khác, cũng đang truy cập cùng một dữ liệu và cũng bị khóa bởi cùng một mutex. Trong trường hợp này, bạn vẫn đang trong quá trình truy cập dữ liệu và bạn có thể mất 15 giây nữa để mở khóa mutex (để luồng khác bị chặn trong khóa mutex sẽ bỏ chặn và sẽ cho phép điều khiển truy cập dữ liệu). Bạn có bằng bất cứ giá nào cho phép một luồng khác chỉ mở khóa cùng một mutex không, và lần lượt, cho phép luồng đang chờ (chặn) trong khóa mutex để bỏ chặn và truy cập dữ liệu? Hy vọng bạn có những gì tôi đang nói ở đây? Theo, đồng ý với định nghĩa phổ quát!,
Vì vậy, nếu bạn rất đặc biệt về việc sử dụng semaphore nhị phân thay vì mutex, thì bạn nên rất cẩn thận trong phạm vi phạm vi khóa các khóa và mở khóa. Ý tôi là, mọi luồng điều khiển chạm vào mọi khóa đều phải thực hiện một cuộc gọi mở khóa, cũng không nên có bất kỳ khóa mở khóa đầu tiên nào, thay vào đó, nó phải luôn luôn là khóa đầu tiên.
Mutex được sử dụng cho "Cơ chế khóa". một quá trình tại một thời điểm có thể sử dụng tài nguyên được chia sẻ
trong khi
Semaphores được sử dụng cho "Cơ chế báo hiệu" như "Tôi đã hoàn thành, bây giờ có thể tiếp tục"
Quan niệm:
Một vài bài báo nói rằng "semaphore nhị phân và mutex giống nhau" hoặc "Semaphore với giá trị 1 là mutex" nhưng sự khác biệt cơ bản là Mutex chỉ có thể được phát hành bởi luồng đã thu được nó, trong khi bạn có thể báo hiệu semaphore từ bất kỳ luồng nào khác
Những điểm chính:
• Một chuỗi có thể có được nhiều hơn một khóa (Mutex).
• Một mutex có thể bị khóa nhiều lần chỉ khi một mutex đệ quy, ở đây khóa và mở khóa cho mutex phải giống nhau
• Nếu một chuỗi đã khóa mutex, cố gắng khóa mutex lại, nó sẽ vào danh sách chờ của mutex đó, dẫn đến bế tắc.
• semaphore nhị phân và mutex giống nhau nhưng không giống nhau.
• Mutex hoạt động tốn kém do các giao thức bảo vệ liên quan đến nó.
• Mục đích chính của mutex là đạt được quyền truy cập nguyên tử hoặc khóa tài nguyên
Một Mutex kiểm soát quyền truy cập vào một nguồn tài nguyên được chia sẻ duy nhất. Nó cung cấp các hoạt động để có được () quyền truy cập vào tài nguyên đó và giải phóng () nó khi hoàn thành.
Một Semaphore kiểm soát quyền truy cập vào hồ bơi chung các nguồn tài nguyên. Nó cung cấp các hoạt động cho Wait () cho đến khi một trong các tài nguyên trong nhóm trở nên khả dụng và Signal () khi được đưa trở lại nhóm.
Khi số lượng tài nguyên mà Semaphore bảo vệ lớn hơn 1, nó được gọi là Semaphore đếm . Khi nó kiểm soát một tài nguyên, nó được gọi là Semaphore Boolean . Một semaphore boolean tương đương với một mutex.
Do đó, Semaphore là một mức độ trừu tượng cao hơn Mutex. Một Mutex có thể được thực hiện bằng cách sử dụng Semaphore nhưng không phải là cách khác.
Câu hỏi được sửa đổi là - Sự khác biệt giữa một mutex và một semaphore "nhị phân" trong "Linux" là gì?
Trả lời: Sau đây là những khác biệt - i) Phạm vi - Phạm vi của mutex nằm trong một không gian địa chỉ quy trình đã tạo ra nó và được sử dụng để đồng bộ hóa các luồng. Trong khi semaphore có thể được sử dụng trên không gian quá trình và do đó nó có thể được sử dụng để đồng bộ hóa quá trình.
ii) Mutex nhẹ và nhanh hơn semaphore. Futex thậm chí còn nhanh hơn.
iii) Mutex có thể được mua lại bởi cùng một chủ đề thành công nhiều lần với điều kiện là nó sẽ phát hành cùng một số lần. Chủ đề khác cố gắng để có được sẽ chặn. Trong trường hợp semaphore nếu cùng một quá trình cố gắng để có được nó một lần nữa thì nó bị chặn vì nó chỉ có thể được mua một lần.
Khác biệt giữa Semaphore nhị phân và Mutex: OWNERSHIP: Semaphores có thể được báo hiệu (đăng) ngay cả từ một chủ sở hữu không hiện tại. Nó có nghĩa là bạn có thể chỉ cần đăng từ bất kỳ chủ đề khác, mặc dù bạn không phải là chủ sở hữu.
Semaphore là một tài sản công cộng trong quá trình, Nó có thể được đăng đơn giản bởi một chủ đề không phải chủ sở hữu. Vui lòng đánh dấu sự khác biệt này trong các chữ cái BÓNG, nó có nghĩa là rất nhiều.
Mutex hoạt động để chặn khu vực quan trọng, nhưng Semaphore hoạt động rất tốt.
http://www.geekforgeek.org/archives/9102 thảo luận chi tiết.
Mutex
là cơ chế khóa được sử dụng để đồng bộ hóa truy cập vào tài nguyên.
Semaphore
là cơ chế báo hiệu.
Tùy thuộc vào lập trình viên nếu anh ấy / cô ấy muốn sử dụng semaphore nhị phân thay cho mutex.
Ngoài thực tế là các mutexes có chủ sở hữu, hai đối tượng có thể được tối ưu hóa cho việc sử dụng khác nhau. Mutexes được thiết kế để được tổ chức chỉ trong một thời gian ngắn; vi phạm điều này có thể gây ra hiệu suất kém và lập kế hoạch không công bằng. Ví dụ, một luồng đang chạy có thể được phép có được một mutex, mặc dù một luồng khác đã bị chặn trên nó. Semaphores có thể cung cấp công bằng hơn, hoặc công bằng có thể bị buộc sử dụng một số biến điều kiện.
sem_post()
cho SCHED_FIFO
và SCHED_RR
(cả hai đều không mặc định): các chủ đề ưu tiên cao nhất, và nếu có nhiều với các ưu tiên như nhau, các chủ đề đã được chờ đợi lâu nhất. OpenSolaris tuân theo quy tắc FIFO này ở một mức độ nào đó ngay cả đối với việc lập lịch trình bình thường. Đối với glibc và FreeBSD, việc mở khóa một mutex đơn giản (nghĩa là không ưu tiên bảo vệ hoặc kế thừa ưu tiên) và đăng một semaphore về cơ bản là giống nhau, đánh dấu đối tượng là đã mở khóa và sau đó, nếu có thể có các chuỗi chờ, hãy gọi kernel để đánh thức.
Trong cửa sổ sự khác biệt là như dưới đây. MUTEX: quá trình thực hiện thành công chờ đợi phải thực hiện tín hiệu và ngược lại. CÁC HÌNH ẢNH BÌNH LUẬN: Các quy trình khác nhau có thể thực hiện thao tác chờ hoặc tín hiệu trên một semaphore.
Mặc dù một semaphore nhị phân có thể được sử dụng như một mutex, một mutex là một trường hợp sử dụng cụ thể hơn, trong đó chỉ có quá trình khóa mutex được cho là để mở khóa nó. Hạn chế quyền sở hữu này giúp bảo vệ chống lại:
Những ràng buộc này không phải lúc nào cũng có mặt vì chúng làm giảm tốc độ. Trong quá trình phát triển mã của bạn, bạn có thể kích hoạt các kiểm tra này tạm thời.
ví dụ: bạn có thể bật thuộc tính Kiểm tra lỗi trong mutex của bạn. Lỗi khi kiểm tra mutexes trở lại EDEADLK
nếu bạn cố gắng khóa cùng một lần hai lần và EPERM
nếu bạn mở khóa một mutex không phải của bạn.
pthread_mutex_t mutex;
pthread_mutexattr_t attr;
pthread_mutexattr_init (&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_ERRORCHECK_NP);
pthread_mutex_init (&mutex, &attr);
Sau khi khởi tạo, chúng ta có thể đặt các kiểm tra này vào mã của mình như sau:
if(pthread_mutex_unlock(&mutex)==EPERM)
printf("Unlock failed:Mutex not owned by this thread\n");
Khái niệm này là rõ ràng với tôi sau khi đi qua bài viết trên. Nhưng có một số câu hỏi còn sót lại. Vì vậy, tôi đã viết đoạn mã nhỏ này.
Khi chúng tôi cố gắng đưa ra một semaphore mà không lấy nó, nó sẽ đi qua. Nhưng, khi bạn cố gắng đưa ra một mutex mà không lấy nó, nó đã thất bại. Tôi đã thử nghiệm điều này trên nền tảng Windows. Cho phép USE_MUTEX chạy cùng mã bằng MUTEX.
#include <stdio.h>
#include <windows.h>
#define xUSE_MUTEX 1
#define MAX_SEM_COUNT 1
DWORD WINAPI Thread_no_1( LPVOID lpParam );
DWORD WINAPI Thread_no_2( LPVOID lpParam );
HANDLE Handle_Of_Thread_1 = 0;
HANDLE Handle_Of_Thread_2 = 0;
int Data_Of_Thread_1 = 1;
int Data_Of_Thread_2 = 2;
HANDLE ghMutex = NULL;
HANDLE ghSemaphore = NULL;
int main(void)
{
#ifdef USE_MUTEX
ghMutex = CreateMutex( NULL, FALSE, NULL);
if (ghMutex == NULL)
{
printf("CreateMutex error: %d\n", GetLastError());
return 1;
}
#else
// Create a semaphore with initial and max counts of MAX_SEM_COUNT
ghSemaphore = CreateSemaphore(NULL,MAX_SEM_COUNT,MAX_SEM_COUNT,NULL);
if (ghSemaphore == NULL)
{
printf("CreateSemaphore error: %d\n", GetLastError());
return 1;
}
#endif
// Create thread 1.
Handle_Of_Thread_1 = CreateThread( NULL, 0,Thread_no_1, &Data_Of_Thread_1, 0, NULL);
if ( Handle_Of_Thread_1 == NULL)
{
printf("Create first thread problem \n");
return 1;
}
/* sleep for 5 seconds **/
Sleep(5 * 1000);
/*Create thread 2 */
Handle_Of_Thread_2 = CreateThread( NULL, 0,Thread_no_2, &Data_Of_Thread_2, 0, NULL);
if ( Handle_Of_Thread_2 == NULL)
{
printf("Create second thread problem \n");
return 1;
}
// Sleep for 20 seconds
Sleep(20 * 1000);
printf("Out of the program \n");
return 0;
}
int my_critical_section_code(HANDLE thread_handle)
{
#ifdef USE_MUTEX
if(thread_handle == Handle_Of_Thread_1)
{
/* get the lock */
WaitForSingleObject(ghMutex, INFINITE);
printf("Thread 1 holding the mutex \n");
}
#else
/* get the semaphore */
if(thread_handle == Handle_Of_Thread_1)
{
WaitForSingleObject(ghSemaphore, INFINITE);
printf("Thread 1 holding semaphore \n");
}
#endif
if(thread_handle == Handle_Of_Thread_1)
{
/* sleep for 10 seconds */
Sleep(10 * 1000);
#ifdef USE_MUTEX
printf("Thread 1 about to release mutex \n");
#else
printf("Thread 1 about to release semaphore \n");
#endif
}
else
{
/* sleep for 3 secconds */
Sleep(3 * 1000);
}
#ifdef USE_MUTEX
/* release the lock*/
if(!ReleaseMutex(ghMutex))
{
printf("Release Mutex error in thread %d: error # %d\n", (thread_handle == Handle_Of_Thread_1 ? 1:2),GetLastError());
}
#else
if (!ReleaseSemaphore(ghSemaphore,1,NULL) )
{
printf("ReleaseSemaphore error in thread %d: error # %d\n",(thread_handle == Handle_Of_Thread_1 ? 1:2), GetLastError());
}
#endif
return 0;
}
DWORD WINAPI Thread_no_1( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_1);
return 0;
}
DWORD WINAPI Thread_no_2( LPVOID lpParam )
{
my_critical_section_code(Handle_Of_Thread_2);
return 0;
}
Thực tế là semaphore cho phép bạn báo hiệu "nó được thực hiện bằng cách sử dụng tài nguyên", mặc dù nó không bao giờ sở hữu tài nguyên, khiến tôi nghĩ rằng có một sự kết hợp rất lỏng lẻo giữa việc sở hữu và báo hiệu trong trường hợp semaphores.
Mutex được sử dụng để bảo vệ mã và dữ liệu nhạy cảm, semaphore được sử dụng để đồng bộ hóa. Bạn cũng có thể sử dụng thực tế với bảo vệ mã nhạy cảm, nhưng có thể có rủi ro giải phóng sự bảo vệ của luồng khác bằng thao tác V.So Chính Sự khác biệt giữa bi-semaphore và mutex là quyền sở hữu. Ví dụ, bằng nhà vệ sinh, Mutex giống như người ta có thể vào nhà vệ sinh và khóa cửa, không ai khác có thể vào cho đến khi người đàn ông ra ngoài, bi-semaphore giống như người ta có thể vào nhà vệ sinh và khóa cửa, nhưng người khác có thể vào bằng cách yêu cầu quản trị viên mở cửa, thật nực cười.
Mutex
Mutexes thường được sử dụng để tuần tự truy cập vào một phần của mã đăng ký lại mà không thể được thực thi đồng thời bởi nhiều hơn một luồng. Một đối tượng mutex chỉ cho phép một luồng vào một phần được kiểm soát, buộc các luồng khác cố gắng truy cập vào phần đó để đợi cho đến khi luồng đầu tiên thoát khỏi phần đó. Việc sử dụng mutex là để bảo vệ tài nguyên được chia sẻ có thể gây nguy hiểm tác dụng phụ ngoài ý muốn. Bất kỳ hai nhiệm vụ RTOS nào hoạt động ở các mức độ ưu tiên khác nhau và phối hợp thông qua một mutex, tạo ra cơ hội đảo ngược ưu tiên . Mutex hoạt động trong không gian người dùng .
Semaphore
Semaphore là một cơ chế báo hiệu. Semaphore hạn chế số lượng người dùng đồng thời của một tài nguyên được chia sẻ lên đến số lượng tối đa. Các chủ đề có thể yêu cầu quyền truy cập vào tài nguyên (giảm semaphore) và có thể báo hiệu rằng chúng đã kết thúc bằng cách sử dụng tài nguyên (tăng semaphore). Nó cho phép số lượng luồng truy cập vào các tài nguyên được chia sẻ. Việc sử dụng chính xác một semaphore là để báo hiệu từ một nhiệm vụ này sang một nhiệm vụ khác. Cũng có thể được sử dụng để báo hiệu từ một thói quen dịch vụ ngắt (ISR) đến một nhiệm vụ. Báo hiệu một semaphore là một hành vi RTOS không chặn và do đó ISR an toàn. Bởi vì kỹ thuật này giúp loại bỏ nhu cầu dễ bị lỗi để vô hiệu hóa các ngắt ở cấp độ nhiệm vụ. Điều này hoạt động trong không gian kernel .
Câu trả lời có thể phụ thuộc vào hệ điều hành đích. Ví dụ: ít nhất một triển khai RTOS mà tôi quen thuộc sẽ cho phép nhiều hoạt động "nhận" tuần tự đối với một mutex OS duy nhất, miễn là tất cả chúng đều nằm trong cùng một bối cảnh luồng. Bội số phải được thay thế bằng số lần đặt bằng nhau trước khi một luồng khác sẽ được phép lấy mutex. Điều này khác với các ngữ nghĩa nhị phân, chỉ cho phép một lần lấy duy nhất tại một thời điểm, bất kể bối cảnh luồng.
Ý tưởng đằng sau loại mutex này là bạn bảo vệ một đối tượng bằng cách chỉ cho phép một bối cảnh duy nhất sửa đổi dữ liệu tại một thời điểm. Ngay cả khi luồng nhận được mutex và sau đó gọi một hàm sửa đổi thêm đối tượng (và nhận / đặt mutex bảo vệ xung quanh các hoạt động của chính nó), các hoạt động vẫn sẽ an toàn vì tất cả đều diễn ra trong một luồng.
{
mutexGet(); // Other threads can no longer get the mutex.
// Make changes to the protected object.
// ...
objectModify(); // Also gets/puts the mutex. Only allowed from this thread context.
// Make more changes to the protected object.
// ...
mutexPut(); // Finally allows other threads to get the mutex.
}
Tất nhiên, khi sử dụng tính năng này, bạn phải chắc chắn rằng tất cả các truy cập trong một luồng thực sự an toàn!
Tôi không chắc mức độ phổ biến của phương pháp này, hoặc liệu nó có áp dụng bên ngoài các hệ thống mà tôi quen thuộc không. Để biết ví dụ về loại mutex này, hãy xem ThreadX RTOS.
Mutexes có quyền sở hữu, không giống như semaphores. Mặc dù bất kỳ luồng nào, trong phạm vi của một mutex, có thể có được một mutex đã được mở khóa và khóa truy cập vào cùng một phần quan trọng của mã, chỉ có luồng đã khóa một mutex mới mở khóa nó .
Như nhiều người ở đây đã đề cập, một mutex được sử dụng để bảo vệ một đoạn mã quan trọng (phần quan trọng của AKA.) Bạn sẽ có được mutex (khóa), nhập phần quan trọng và giải phóng mutex (mở khóa) tất cả trong cùng một luồng .
Trong khi sử dụng semaphore, bạn có thể tạo một luồng chờ trên semaphore (nói luồng A), cho đến khi một luồng khác (nói luồng B) hoàn thành bất kỳ nhiệm vụ nào, sau đó đặt Semaphore cho luồng A dừng chờ và tiếp tục nhiệm vụ của nó.
Giải pháp tốt nhất
Sự khác biệt duy nhất là
1.Mutex -> khóa và mở khóa thuộc quyền sở hữu của một chuỗi khóa mutex.
2.Semaphore -> Không có quyền sở hữu tức là; nếu một luồng gọi semwait (s) thì bất kỳ luồng nào khác có thể gọi sempost (s) để loại bỏ khóa.
MUTEX
Cho đến gần đây, khóa ngủ duy nhất trong kernel là semaphore. Hầu hết những người sử dụng semaphores đã tạo ra một semaphore với số lượng một và coi chúng như một khóa loại trừ lẫn nhau, một phiên bản ngủ của khóa xoay. Thật không may, semaphores khá chung chung và không áp đặt bất kỳ ràng buộc sử dụng. Điều này làm cho chúng hữu ích để quản lý quyền truy cập độc quyền trong các tình huống tối nghĩa, chẳng hạn như các điệu nhảy phức tạp giữa kernel và không gian người dùng. Nhưng điều đó cũng có nghĩa là việc khóa đơn giản sẽ khó thực hiện hơn và việc thiếu các quy tắc được thi hành khiến cho bất kỳ loại gỡ lỗi tự động hoặc thực thi ràng buộc nào đều không thể thực hiện được. Tìm kiếm một khóa ngủ đơn giản hơn, các nhà phát triển kernel đã giới thiệu mutex.Yes, như bạn đã quen với, đó là một cái tên khó hiểu. Chúng ta hãy làm rõ. Thuật ngữ này là một tên chung để chỉ bất kỳ khóa ngủ nào thực thi loại trừ lẫn nhau, chẳng hạn như một semaphore với số lượng sử dụng là một. Trong các nhân Linux gần đây, danh từ thích hợp mut mutex bây giờ cũng là một loại khóa ngủ cụ thể thực hiện loại trừ lẫn nhau. Đó là, một mutex là một mutex.
Sự đơn giản và hiệu quả của mutex đến từ các ràng buộc bổ sung mà nó áp đặt cho người dùng của nó hơn và hơn những gì semaphore yêu cầu. Không giống như semaphore, thực hiện hành vi cơ bản nhất theo thiết kế ban đầu của Dijkstra, mutex có trường hợp sử dụng chặt chẽ hơn, hẹp hơn: n Mỗi lần chỉ có một nhiệm vụ có thể giữ mutex. Đó là, số lượng sử dụng trên một mutex luôn luôn là một.
[1] Phát triển nhân Linux, phiên bản thứ ba Robert Love
Tôi nghĩ rằng hầu hết các câu trả lời ở đây đều khó hiểu, đặc biệt là những câu nói rằng mutex chỉ có thể được phát hành bởi quá trình giữ nó nhưng semaphore có thể được báo hiệu bởi quá trình ay. Dòng trên là loại mơ hồ về semaphore. Để hiểu chúng ta nên biết rằng có hai loại semaphore được gọi là semaphore và loại kia được gọi là semaphore nhị phân. Khi đếm semaphore, quyền truy cập vào n số tài nguyên trong đó n có thể được xác định trước khi sử dụng. Mỗi semaphore có một biến đếm, giữ cho số lượng tài nguyên được sử dụng, ban đầu, nó được đặt thành n. Mỗi quá trình muốn sử dụng một tài nguyên thực hiện một hoạt động Wait () trên semaphore (do đó làm giảm số lượng). Khi một quá trình giải phóng một tài nguyên, nó thực hiện một hoạt động phát hành () (tăng số lượng). Khi số đếm trở thành 0, tất cả các tài nguyên đang được sử dụng. Sau đó, quá trình đợi cho đến khi số đếm trở thành hơn 0. Bây giờ đây chỉ là quá trình giữ tài nguyên có thể tăng số lượng mà không quá trình nào khác có thể tăng số lượng, chỉ các quy trình giữ tài nguyên có thể tăng số lượng và quy trình chờ đợi semaphore kiểm tra lại và khi thấy tài nguyên có sẵn, nó sẽ giảm số lần nữa. Vì vậy, về mặt semaphore nhị phân, chỉ có quá trình giữ semaphore mới có thể tăng số lượng và số lượng vẫn bằng không cho đến khi nó ngừng sử dụng semaphore và tăng số lượng và quá trình khác có cơ hội truy cập vào semaphore. Bây giờ đây là chỉ bắt quá trình giữ tài nguyên có thể tăng số lượng, không có quy trình nào khác có thể tăng số lượng, chỉ các quy trình giữ tài nguyên có thể tăng số lượng và quá trình chờ semaphore kiểm tra lại và khi thấy tài nguyên có sẵn giảm số lượng một lần nữa. Vì vậy, về mặt semaphore nhị phân, chỉ có quá trình giữ semaphore mới có thể tăng số lượng và số lượng vẫn bằng không cho đến khi nó ngừng sử dụng semaphore và tăng số lượng và quá trình khác có cơ hội truy cập vào semaphore. Bây giờ đây là chỉ bắt quá trình giữ tài nguyên có thể tăng số lượng, không có quy trình nào khác có thể tăng số lượng, chỉ các quy trình giữ tài nguyên có thể tăng số lượng và quá trình chờ semaphore kiểm tra lại và khi thấy tài nguyên có sẵn giảm số lượng một lần nữa. Vì vậy, về mặt semaphore nhị phân, chỉ có quá trình giữ semaphore mới có thể tăng số lượng và số lượng vẫn bằng không cho đến khi nó ngừng sử dụng semaphore và tăng số lượng và quá trình khác có cơ hội truy cập vào semaphore.
Sự khác biệt chính giữa semaphore nhị phân và mutex là semaphore là một cơ chế báo hiệu và mutex là một cơ chế khóa, nhưng semaphore nhị phân dường như hoạt động như mutex tạo ra sự nhầm lẫn, nhưng cả hai đều là các khái niệm khác nhau phù hợp cho một loại công việc khác nhau.