2010-10-20 45 views
16

Tôi đã đọc trên đa luồng và chia sẻ tài nguyên truy cập và một trong nhiều (đối với tôi) khái niệm mới là khóa mutex. Những gì tôi dường như không thể tìm ra là những gì đang thực sự xảy ra với các chủ đề mà tìm thấy một "phần quan trọng" bị khóa. Nó nói ở nhiều nơi mà thread bị "chặn", nhưng điều đó có nghĩa là gì? Nó bị đình chỉ, và nó sẽ tiếp tục khi khóa được nâng lên? Hay nó sẽ thử lại trong lần lặp tiếp theo của "vòng lặp chạy"? Lý do tôi hỏi, là vì tôi muốn có các sự kiện do hệ thống cung cấp (chuột, bàn phím, v.v.), được phân phối trên luồng chính, được xử lý trong một phần rất cụ thể trong vòng lặp chạy của chuỗi phụ của tôi. Vì vậy, bất kỳ sự kiện nào được phân phối, tôi đều xếp hàng trong cơ sở dữ liệu của riêng mình. Rõ ràng, datastructure cần một khóa mutex bởi vì nó đang được sửa đổi bởi cả hai luồng. Mảnh ghép còn thiếu là: điều gì xảy ra khi một sự kiện được phân phối trong một hàm trên chuỗi chính, tôi muốn xếp hàng nó, nhưng hàng đợi bị khóa? Chủ đề chính sẽ bị treo, hay nó sẽ nhảy qua phần bị khóa và đi ra khỏi phạm vi (mất sự kiện)?Khóa Mutex: "chặn" nghĩa là gì?

Trả lời

11

Thực thi phương tiện bị chặn bị kẹt ở đó; nói chung, các chủ đề được đưa vào giấc ngủ của hệ thống và sản xuất bộ vi xử lý cho chủ đề khác. Khi một thread bị chặn cố gắng để có được một mutex, thực thi tiếp tục khi mutex được phát hành, mặc dù thread có thể chặn lại nếu thread khác lấy mutex trước khi nó có thể.

Thường có hoạt động thử khóa để lấy mutex nếu có thể và nếu không, sẽ trả về lỗi. Nhưng cuối cùng bạn sẽ phải di chuyển sự kiện hiện tại vào hàng đợi đó. Ngoài ra, nếu bạn trì hoãn di chuyển các sự kiện đến chuỗi nơi chúng được xử lý, ứng dụng sẽ không phản hồi bất kể.

Hàng đợi thực sự là một trường hợp bạn có thể thoát khỏi khi không sử dụng mutex. Ví dụ: Mac OS X (và có thể cả iOS) cung cấp các chức năng OSAtomicEnqueue()OSAtomicDequeue() (xem man atomic hoặc <libkern/OSAtomic.h>) khai thác các hoạt động nguyên tử dành riêng cho bộ xử lý để tránh sử dụng khóa.

Nhưng, tại sao không chỉ xử lý các sự kiện trên sợi chính như một phần của vòng lặp chạy chính?

+0

Vòng lặp chính không phải là điều thúc đẩy ứng dụng. Tôi đang trên Mac OSX và sử dụng một CVDisplayLink mà hiệu quả là sinh ra một sợi riêng biệt (ưu tiên cao) mà lần lượt sẽ lái vòng lặp chạy của tôi. Sự kiện, như tôi đã hiểu, sẽ được phân phối trên luồng chính, vì vậy việc đồng bộ hóa dường như theo thứ tự. – zmippie

1

Chặn chỉ có nghĩa là. Nó bị chặn. Nó sẽ không tiến hành cho đến khi có thể. Bạn không nói ngôn ngữ nào bạn đang sử dụng, nhưng hầu hết các ngôn ngữ/thư viện đều khóa các đối tượng nơi bạn có thể "cố gắng" lấy khóa và sau đó tiếp tục và làm điều gì đó khác nhau tùy thuộc vào việc bạn đã thành công hay không.

Nhưng trong ví dụ, khối Java được đồng bộ hóa, chuỗi của bạn sẽ dừng lại cho đến khi có thể lấy được màn hình (mutex, lock). Giao diện java.util.concurrent.locks.Lock mô tả các đối tượng khóa có tính linh hoạt hơn trong việc mua lại khóa.

6

Cách đơn giản nhất để nghĩ về nó là chủ đề bị chặn được đặt trong trạng thái chờ ("ngủ") cho đến khi chuỗi được giữ bởi chuỗi đang giữ nó. Vào thời điểm đó, hệ điều hành sẽ "đánh thức" một trong những chủ đề chờ đợi trên mutex và để cho nó có được nó và tiếp tục. Nó giống như hệ điều hành chỉ đơn giản là đặt các chủ đề bị chặn trên một kệ cho đến khi nó có những thứ nó cần phải tiếp tục. Cho đến khi hệ điều hành lấy sợi ra khỏi giá, nó không làm gì cả. Việc triển khai chính xác - chuỗi nào sẽ được tiếp theo, cho dù tất cả họ có được đánh thức hay họ đang xếp hàng - sẽ phụ thuộc vào hệ điều hành của bạn và ngôn ngữ/khung mà bạn đang sử dụng.

+0

Vì vậy, những gì chính xác là sự khác biệt trong bị chặn hoặc chờ đợi, chúng có giống nhau không? – Celeritas

0

Quá muộn để trả lời nhưng tôi có thể tạo điều kiện cho sự hiểu biết. Tôi đang nói nhiều hơn từ quan điểm thực hiện hơn là văn bản lý thuyết.

Từ "chặn" là loại từ đồng nghĩa kỹ thuật.Mọi người có thể sử dụng nó cho ngủ hoặc chỉ đang chờ. Thuật ngữ này phải được hiểu trong ngữ cảnh sử dụng.

Phương tiện chặn Đang chờ - Giả sử trên hệ thống SMP, luồng A muốn mua ổ khóa do một số sợi khác nắm giữ B. Một trong các cơ chế là vô hiệu hóa và tiếp tục quay trên bộ xử lý trừ khi B nhận được. Một cơ chế khác có thể, một cơ chế hiệu quả, là cho phép các luồng khác sử dụng bộ vi xử lý, trong trường hợp B không nhận được nó một cách dễ dàng. Vì vậy, chúng tôi lên lịch trình B (như preemption được kích hoạt) và cung cấp cho bộ vi xử lý cho một số chủ đề khác C. Trong trường hợp này thread B chỉ đợi trong hàng đợi của scheduler và quay trở lại với lượt của nó. Hiểu rằng B không ngủ chỉ chờ đợi thay vì thụ động thay vì các chu kỳ xử lý bận và chờ. Trên các hệ thống BSD và Solaris có các cấu trúc dữ liệu như turnstiles để thực hiện tình huống này.

phương tiện Chặn Ngủ - Nếu thread B đã thay bằng cuộc gọi hệ thống như read() chờ đợi dữ liệu từ ổ cắm mạng, nó không thể tiến hành cho đến khi nó được nó. Do đó, một số văn bản tình cờ sử dụng chặn cụm từ là "... bị chặn cho I/O" hoặc "... trong chặn cuộc gọi hệ thống". Trên thực tế, thread B là khá ngủ. Có các cấu trúc dữ liệu cụ thể được gọi là hàng đợi ngủ - giống như các phòng chờ sang trọng trên cổng hàng không :-). Các chủ đề sẽ được đánh thức khi hệ điều hành phát hiện sẵn có của dữ liệu, giống như một tiếp viên của phòng chờ.