Thay thế cho hàng đợi trong RTOS


12

Để liên lạc giữa các tác vụ hoặc để chia sẻ dữ liệu giữa hai tác vụ của RTOS, chúng tôi sử dụng Hàng đợi. Nhưng vấn đề với Hàng đợi là chúng chậm .... Họ sao chép dữ liệu trong Bộ đệm sau đó Xử lý Mutex và sau đó Truyền dữ liệu. Thật khó chịu nếu bạn phải truyền dữ liệu lớn. Một vấn đề khác là nếu cùng một hàng đợi được truy cập bởi nhiều tác vụ. Sau đó, Ảnh trở thành như sau: - Đầu tiên Đợi để có quyền truy cập vào Hàng đợi sau đó Xếp hàng Xử lý Mutex nội bộ sau đó Truyền dữ liệu.

Điều này làm tăng chi phí trên hệ thống. Điều gì có thể là sự thay thế hiệu quả cho hàng đợi?

(Tôi đoán câu hỏi này là Độc lập của RTOS mà chúng tôi sử dụng. Hầu hết các RTOS chỉ xử lý Hàng đợi theo cách này)


Bạn có ý nghĩa gì bởi một hàng đợi được truy cập bởi nhiều tác vụ? Bạn có nghĩa là đăng lên hàng đợi hoặc đọc từ hàng đợi? Nhiều tác vụ sẽ có thể đăng lên hàng đợi với chi phí tối thiểu. RTOS nên xử lý việc thay đổi để bài viết là một hoạt động nguyên tử. Đối với 99% nhiệm vụ, bạn nên có một vòng lặp dành cho hàng đợi và xử lý tin nhắn. Một hàng đợi chỉ (thường) chỉ được đọc bởi một nhiệm vụ. Bạn có thể cần phải xem thiết kế của bạn và cách bạn đang sử dụng hàng đợi thay vì thay thế chúng.
Erik

@Erik: Xin lỗi! Tôi đang sử dụng cơ chế mà bạn đề cập .... Tôi muốn nói điều khác và tôi đã viết khác .... Tôi sẽ chỉnh sửa điều đó !! Cảm ơn đã chỉ ra sai lầm! Tôi đang chờ truy cập hàng đợi trong mã của tôi!
Swanand

Câu trả lời:


7

Hàng đợi hoạt động theo cách đó bởi vì đó là mô hình giao dịch an toàn luồng cho giao tiếp giữa các tác vụ. Bạn có nguy cơ tham nhũng dữ liệu và / hoặc các vấn đề sở hữu trong bất kỳ chương trình ít nghiêm ngặt hơn.

Bạn đang sao chép dữ liệu vào bộ đệm trong bộ nhớ rồi truyền con trỏ với các thành phần hàng đợi hay cố gắng truyền tất cả dữ liệu trong chính các thành phần hàng đợi? Nếu bạn không chuyển con trỏ thì bạn sẽ tăng hiệu suất làm việc đó thay vì truyền từng byte một lần thông qua các phần tử hàng đợi.


2
Tôi sẽ nói điều tương tự. Nếu bạn chỉ truyền con trỏ đến dữ liệu trong hàng đợi, bạn có thể tăng tốc độ, nhưng đảm bảo rằng bạn không kết thúc với hai luồng cố gắng sử dụng và thay đổi dữ liệu.
Kortuk

Như @Kortuk đã nói, tôi cần "đảm bảo rằng bạn không kết thúc với hai luồng cố gắng sử dụng và thay đổi dữ liệu" ... Điều đó có nghĩa là tăng chi phí ... Tôi không muốn xử lý nhiều! :(
Swanand

Vì vậy, Không có sự thay thế nào như vậy cho Hàng đợi ... Thay vì Hàng đợi Dữ liệu, tôi cần sử dụng Hàng đợi Con trỏ!
Swanand

1
@Swanand nếu lập kế hoạch cho ứng dụng của bạn sao cho hàng đợi chỉ là một hướng (nghĩa là bạn không bao giờ đọc cùng một hàng đợi trong hai tác vụ) và bạn xử lý dữ liệu được lưu trữ tại con trỏ ngay lập tức, sau đó bạn không gặp vấn đề gì với việc chia sẻ dữ liệu. Sẽ có chi phí gia tăng khi bạn có thể phải tạo nhiều hàng đợi để truyền dữ liệu qua lại một cách đáng tin cậy nhưng đây là chi phí kinh doanh trong môi trường đa tác vụ.
AngryEE

7

Một cách dễ dàng là đặt một con trỏ tới dữ liệu trên hàng đợi và sử dụng dữ liệu bằng con trỏ.

Lưu ý rằng bạn đang giao dịch an toàn cho hiệu suất theo cách này vì bạn phải đảm bảo rằng:

  1. bộ đệm vẫn còn hiệu lực cho đến khi người tiêu dùng đã sử dụng dữ liệu
  2. ai đó giải phóng bộ đệm

Nếu bạn không sử dụng bộ nhớ được cấp phát động, bạn không phải phân bổ bộ nhớ, nhưng bạn vẫn phải đảm bảo rằng vùng nhớ không được sử dụng lại trước khi dữ liệu được sử dụng.


6

Hàng đợi không khóa có thể được triển khai cho trường hợp một nhà sản xuất / một người tiêu dùng và thường bạn có thể kiến ​​trúc phần mềm của mình để giảm thiểu số lượng hàng đợi nhiều nhà sản xuất hoặc nhiều người tiêu dùng.

Một hàng đợi không khóa có thể được xây dựng như vậy: Phân bổ một mảng các phần tử sẽ được truyền đạt, và hai số nguyên, gọi chúng là Head and Tail. Head là một chỉ mục vào mảng, trong đó mục tiếp theo sẽ được thêm vào. Đuôi là một chỉ mục vào mảng, trong đó mục tiếp theo có sẵn để được loại bỏ. Nhiệm vụ của nhà sản xuất đọc H và T để xác định xem có chỗ để thêm một mục hay không; ghi mục vào chỉ mục H, sau đó cập nhật H. Các tác vụ của người tiêu dùng đọc H và T để xác định xem có dữ liệu không, đọc dữ liệu từ chỉ mục T, sau đó cập nhật T. Về cơ bản, đó là bộ đệm vòng được truy cập bởi hai tác vụ và thứ tự các thao tác (chèn, sau đó cập nhật H; xóa, sau đó cập nhật T) đảm bảo rằng dữ liệu không xảy ra.

Nếu bạn gặp tình huống với nhiều nhà sản xuất và một người tiêu dùng, hoặc một nhà sản xuất và nhiều người tiêu dùng, bạn thực sự có một giới hạn tài nguyên thuộc loại nào đó, và không có gì khác ngoài việc sử dụng đồng bộ hóa, vì giới hạn hiệu suất có nhiều khả năng là nhà sản xuất / người tiêu dùng đơn độc hơn một hệ điều hành với cơ chế khóa.

Nhưng nếu bạn có nhiều nhà sản xuất VÀ người tiêu dùng, bạn nên dành thời gian (trong không gian thiết kế) để xem liệu bạn có thể có được một cơ chế giao tiếp phối hợp hơn không; trong trường hợp như thế này, việc tuần tự hóa mọi thứ thông qua một hàng đợi chắc chắn làm cho hiệu quả của hàng đợi là yếu tố quyết định trung tâm của hiệu suất.


1
Tôi đã định +1 cái này, nhưng bạn không chính xác: hàng đợi không khóa có thể thực hiện cho nhiều người đọc và người viết, chúng chỉ phức tạp hơn. (xem bài viết của Michael + Scott về Hàng đợi không khóa google.com/search?q=michael%20scott%20queue )
Jason S

1
@Jason S - giấy Scott có yêu cầu cụ thể quyền đăng ký lại cho các hoạt động chèn và xóa không khóa không? Nếu vậy, nếu bạn có thể trích xuất nó và đăng nó, xin vui lòng, nó sẽ là một tài sản vô giá cho nhiều người. Người đọc cần lưu ý rằng giấy trích dẫn sử dụng các hướng dẫn máy đặc biệt, trong khi vị trí của tôi trong bài viết trên giả định không có hướng dẫn như vậy.
JustJeff

1
Vâng, chi phí của các thuật toán không khóa thường là phụ thuộc vào CAS hoặc các hướng dẫn tương đương. Nhưng làm thế nào để nhập lại vào chơi ở đây? Nó có ý nghĩa đối với mutexes + khóa cấu trúc, nhưng không phải cho các hoạt động cấu trúc dữ liệu.
Jason S

2

Người ta có thể có được hoạt động hiệu quả trong hàng đợi một người tiêu dùng đa nhà sản xuất không khóa nếu chính hàng đợi đó chứa các vật phẩm đủ nhỏ để làm việc với một cửa hàng độc quyền, trao đổi so sánh hoặc tương tự, và người ta có thể sử dụng giá trị dành riêng hoặc giá trị dành riêng cho một vị trí hàng đợi trống. Khi viết vào hàng đợi, người viết thực hiện trao đổi so sánh để cố lưu trữ dữ liệu của mình vào khe trống tiếp theo; nếu thất bại, người viết sẽ thử vị trí sau. Mặc dù hàng đợi duy trì một con trỏ đến vị trí trống tiếp theo, giá trị con trỏ là "lời khuyên". Lưu ý rằng nếu một hệ thống sử dụng trao đổi so sánh thay vì độc quyền tải cửa hàng, có thể cần phải có một 'họ' các giá trị 'khe trống' khác nhau. Mặt khác, nếu giữa thời gian người viết tìm thấy một hàng đợi trống và cố gắng ghi vào đó, một nhà văn khác viết khe và người đọc đọc nó, nhà văn đầu tiên sẽ vô tình đặt dữ liệu của mình vào một nơi mà người đọc sẽ không nhìn thấy nó. Vấn đề này không xảy ra trong các hệ thống sử dụng độc quyền tải cửa hàng, vì độc quyền cửa hàng sẽ phát hiện ra rằng dữ liệu đã được ghi ngay cả khi nó được ghi lại giá trị cũ.


1

Bạn có thể truy cập hàng đợi hiệu quả hơn bằng cách viết lên trên hàng đợi Thông thường, hầu hết các RTOS đều hỗ trợ thêm vào phía trước hàng đợi mà không yêu cầu phải có mutex. Nhưng hãy chắc chắn rằng bạn sử dụng thêm vào phía trước hàng đợi tối thiểu nhất có thể, nơi bạn chỉ muốn thực hiện dữ liệu nhanh hơn. Thông thường các cấu trúc hàng đợi có giới hạn kích thước tối đa, do đó bạn không thể đặt tất cả dữ liệu vào hàng đợi do đó việc vượt qua con trỏ luôn dễ dàng.

chúc mừng !!


1

Hàng đợi vốn không chậm. Việc thực hiện chúng có thể được.

Nếu bạn sao chép dữ liệu một cách mù quáng và sử dụng hàng đợi đồng bộ, bạn sẽ thấy một điểm nhấn hiệu suất.

Như các áp phích khác đã chỉ ra, có những lựa chọn thay thế không khóa. Trường hợp một nhà sản xuất / người tiêu dùng duy nhất là đơn giản; cho nhiều nhà sản xuất và người tiêu dùng, các lock-free thuật toán xếp hàng bởi Michael và Scott (đó là những cái tên cuối cùng của họ) là tiêu chuẩn, và được sử dụng làm cơ sở cho Java ConcurrentLinkedQueue .

Có thể tối ưu hóa nhu cầu xếp hàng trong một số trường hợp nhất định, nhưng chúng cung cấp đảm bảo đồng thời thường mang lại lợi ích đơn giản hóa lớn cho các hệ thống bằng cách cho phép bạn tách rời các tác vụ.


Từ bài báo của Michael & Scott: "đó là thuật toán lựa chọn rõ ràng cho các máy cung cấp nguyên thủy nguyên tử phổ quát (ví dụ: so sánh và trao đổi hoặc tải liên kết / lưu trữ có điều kiện)". Mặc dù điều này có thể không thực sự khóa chính xác một luồng, có một hình thức đồng bộ hóa đang diễn ra ở đây.
JustJeff

bạn có một điểm; nó có thể giảm yêu cầu đồng thời từ quyền truy cập độc quyền vào hàng rào bộ nhớ.
Jason S
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.