2011-01-19 33 views
9

Điều này có phần liên quan đến this question, nhưng tôi nghĩ rằng tôi cần biết thêm một chút nữa. Tôi đã cố gắng để có được đầu của tôi xung quanh làm thế nào để làm điều này trong một vài ngày (trong khi làm việc trên các bộ phận khác), nhưng thời gian đã đến để tôi cắn đạn và nhận được đa luồng. Ngoài ra, tôi có thêm một chút thông tin so với câu hỏi được liên kết.boost :: asio, chủ đề và đồng bộ hóa

Thứ nhất, về đa luồng. Vì tôi đã thử nghiệm mã của mình, tôi đã không làm phiền với bất kỳ luồng đa luồng nào. Nó chỉ là một ứng dụng giao diện điều khiển bắt đầu một kết nối đến một máy chủ thử nghiệm và mọi thứ khác sau đó được xử lý. Vòng lặp chính là:

while(true) 
{ 
    Root::instance().performIO(); // calls io_service::runOne(); 
} 

Khi tôi viết ứng dụng chính của mình, tôi đoán giải pháp này sẽ không được chấp nhận (vì nó sẽ phải được gọi trong vòng lặp thông báo, trong khi có thể, vấn đề khi khối tin nhắn chờ đợi một tin nhắn. Bạn có thể thay đổi nó để vòng lặp tin nhắn không chặn, nhưng sau đó không phải là sẽ whack việc sử dụng CPU thông qua mái nhà?)

Giải pháp nó dường như là ném một luồng khác vào nó. Tốt. Nhưng sau đó tôi đã đọc rằng io_service::run() trả về khi không có việc gì để làm. Đó là gì? Đó có phải là khi không có dữ liệu hoặc không có kết nối? Nếu có ít nhất một kết nối tồn tại thì nó vẫn còn sống? Nếu vậy, đó không phải là quá nhiều của một vấn đề như tôi chỉ có để bắt đầu một chủ đề mới khi kết nối đầu tiên được thực hiện và tôi hạnh phúc nếu tất cả dừng lại khi không có gì đang xảy ra ở tất cả. Tôi đoán tôi bối rối bởi định nghĩa 'không có việc phải làm'.

Sau đó, tôi phải lo lắng về việc đồng bộ hóa chuỗi tăng của mình với luồng GUI chính. Vì vậy, tôi đoán các câu hỏi của tôi là:

  1. Cách thực hành tốt nhất khi sử dụng boost :: asio trong ứng dụng khách có liên quan đến chủ đề và giữ chúng sống như thế nào?
  2. Khi ghi vào ổ cắm từ sợi chính đến luồng IO, đồng bộ hóa có đạt được bằng cách sử dụng boost::asio::post, để cuộc gọi xảy ra sau trong io_service không?
  3. Khi nhận dữ liệu, làm cách nào để mọi người lấy lại dữ liệu cho chuỗi giao diện người dùng? Trong quá khứ khi tôi sử dụng cổng hoàn thành, tôi đã thực hiện một sự kiện đặc biệt có thể đăng dữ liệu trở lại luồng giao diện người dùng chính bằng cách sử dụng :: SendMessage. Nó không thanh lịch, nhưng nó hoạt động.

Tôi sẽ đọc thêm một số ngày hôm nay, nhưng thật tuyệt vời khi có được một người đứng đầu từ một người đã thực hiện việc này. Tài liệu Boost :: asio không tuyệt vời và hầu hết công việc của tôi cho đến nay dựa trên một chút tài liệu, một số thử nghiệm/lỗi, một số mã ví dụ trên web.

Trả lời

6

1) Hãy xem io_service::work. Miễn là một đối tượng công việc tồn tại io_service :: run sẽ không trả về. Vì vậy, nếu bạn bắt đầu làm sạch, phá hủy đối tượng công việc, hủy bỏ bất kỳ hoạt động xuất sắc nào, ví dụ như một async_read trên một socket, chờ chạy để trả về và dọn sạch tài nguyên của bạn.

2) io_service :: bài sẽ thực thi không đồng bộ trình xử lý đã cho từ chuỗi chạy io_service. Một cuộc gọi lại có thể được sử dụng để có được kết quả của hoạt động được thực thi.

3) Bạn cần một số hình thức hệ thống nhắn tin để thông báo cho luồng GUI của bạn về dữ liệu mới. Có một số khả năng ở đây.

Theo như nhận xét của bạn về tài liệu, tôi điều Asio là một trong những thư viện tăng tài liệu tốt hơn và nó đi kèm với các ví dụ rõ ràng.

+0

+1 io_service :: công việc là cách tôi tự giải quyết vấn đề này. –

+0

cảm ơn phản hồi của bạn. Khi bạn nói có một số khả năng, những cái bạn đã sử dụng trong quá khứ là gì? –

+0

@ Moo-Juice, tôi đã không ở trong tình huống có một chuỗi GUI cụ thể cần xử lý dữ liệu. Tôi chỉ sử dụng cơ chế gọi lại và xử lý dữ liệu từ một chuỗi io_service khi nó đến.Một số hình thức của hàng đợi tin nhắn mà các chủ đề gui đọc, có thể được sử dụng để cho biết sự xuất hiện của dữ liệu mới. Hoặc bạn có thể chỉ cần sử dụng biến có điều kiện. Thực sự phụ thuộc vào ứng dụng, thiết kế và yêu cầu của bạn. –

1

boost::io_service::run() sẽ chỉ trả lại khi không có gì để làm, vì vậy không có hoạt động không đồng bộ nào đang chờ xử lý, ví dụ: async chấp nhận/kết nối, async đọc/ghi hoặc hẹn giờ async chờ đợi. vì vậy trước khi gọi io_service::run(), trước tiên bạn phải bắt đầu bất kỳ op không đồng bộ nào.

Tôi chưa có ứng dụng giao diện điều khiển hoặc GUI? trong mọi trường hợp đa luồng trông giống như một overkill. bạn có thể sử dụng Asio kết hợp với vòng lặp tin nhắn của bạn. nếu đó là win32 GUI bạn có thể gọi io_service :: run_one() từ trình xử lý OnIdle() của bạn. trong trường hợp ứng dụng giao diện điều khiển, bạn có thể thiết lập deadline_timer kiểm tra thường xuyên (mỗi 200ms?) cho người dùng nhập và sử dụng nó với io_service::run(). tất cả mọi thứ trong chủ đề duy nhất để đơn giản hóa rất nhiều giải pháp

2

1) cách thực hành tốt nhất của việc sử dụng boost :: ASIO trong một ứng dụng client liên quan đến chủ đề với và giữ họ còn sống là gì?

Là một nhóm chủ đề gọi io_service::run là khả năng mở rộng và dễ triển khai nhất.

2) Khi viết vào một ổ cắm từ chủ đề chính để thread IO, được đồng bộ đạt được sử dụng boost :: ASIO :: bưu điện, để các cuộc gọi xảy ra sau này trong io_service?

Bạn sẽ cần phải sử dụng a strand để bảo vệ bất kỳ trình xử lý nào có thể được gọi bởi nhiều luồng. Xem this answer vì nó có thể giúp bạn, cũng như ví dụ này.

3) Khi nhận dữ liệu, cách mọi người lấy lại dữ liệu cho luồng giao diện người dùng? Trong quá khứ khi tôi sử dụng cổng hoàn thành, Tôi đã thực hiện một sự kiện đặc biệt có thể đăng dữ liệu trở lại chủ đề giao diện người dùng chính bằng cách sử dụng :: SendMessage. Nó không phải là trang nhã, nhưng nó hoạt động.

Cách cung cấp gọi lại dưới dạng boost::function khi bạn đăng sự kiện không đồng bộ lên io_service? Sau đó, trình xử lý sự kiện có thể gọi lại cuộc gọi và cập nhật giao diện người dùng với kết quả.

+0

cảm ơn thông tin này. Vấn đề là các callback của tôi đang được gọi từ luồng gọi là 'io_service :: run', không phải là luồng giao diện người dùng chính. Tôi nghĩ rằng tôi sẽ giải quyết điều này bằng cách có một đại biểu ủy quyền sử dụng SendMessage để gọi một đại biểu khác trên chủ đề giao diện người dùng. Đối với các sợi, tôi đã sử dụng chúng. Tuy nhiên, tôi đã sử dụng 'io_service :: post (strand_.wrap (' chứ không phải là 'strand :: post', điều này không chính xác? –

+0

@ Moo-Juice nó phụ thuộc vào ngữ cảnh mà chúng được sử dụng, cả post và wrap đều rất giống nhau –

+0

tốt, tôi sử dụng ** bài ** ở cấp độ ổ cắm, ví dụ, khi tôi gửi dữ liệu các bài đăng giao diện công khai đến một nội bộ bắt đầu 'async_write_some'. Một sự trừu tượng hóa cao (hàng đợi lệnh được truyền đi) sử dụng ** wrap ** trên các phương thức của nó không chỉ có thể được đăng từ bất kỳ luồng nào, mà nó còn thiết lập thời hạn của riêng nó (để ngăn hàng đợi được gửi quá nhanh) –

0

Khi nhận dữ liệu, mọi người lấy lại dữ liệu về chuỗi giao diện người dùng như thế nào? Trong quá khứ khi tôi sử dụng cổng hoàn thành, tôi đã thực hiện một sự kiện đặc biệt có thể đăng dữ liệu trở lại luồng giao diện người dùng chính bằng cách sử dụng :: SendMessage. Nó không phải là thanh lịch, nhưng nó đã làm việc

:: PostMessage có thể phù hợp hơn.

Trừ khi mọi thứ chạy trong một chuỗi, các cơ chế này phải được sử dụng để đăng sự kiện an toàn lên chuỗi giao diện người dùng.

Các vấn đề liên quan