2012-04-12 8 views
5

Tôi đã gặp một vấn đề thú vị trong ứng dụng C# .Net 4.0 của tôi bằng cách sử dụng lớp SerialPortThreadPool.QueueUserWorkItem hoặc Task s..Net Thread vs ThreadPool vs Task cho SerialPort Communication

Sự cố chỉ xảy ra nếu tôi sử dụng đồng thời 2 hoặc nhiều SerialPort. Mỗi cổng nối tiếp chạy trong thread riêng của mình mà tôi tạo ra trong 1 trong tổng số 3 cách:

  1. new Thread(DoSerialCommX)
  2. ThreadPool.QueueUserWorkItem(DoSerialCommX)
  3. new Task(DoSerialCommX, TaskCreationOptions.LongRunning).Start()

Để minh họa cho vấn đề này, tôi tạo ra phương pháp DoSerialCommX của tôi để đọc và ghi vào cổng nối tiếp mãi mãi trong một vòng lặp. Nó trông giống như thế này: (Tôi không thực sự làm điều này trong chương trình thực sự của tôi. Đây chỉ là một đoạn trích từ chương trình thử nghiệm của tôi mà cô lập và minh họa vấn đề).

private void DoSerialCommX() 
{ 
    SerialPort port = new SerialPort("ComX", 9600); 
    port.Open(); 

    while(true) 
    { 
     //Read and write to serial port 
    } 
} 

Nếu tôi sử dụng một trong hai phương pháp 2 hoặc 3, cửa sổ giao tiếp nối tiếp và tôi nhận được nhiều thời gian chờ liên lạc. Nếu tôi sử dụng phương pháp 1, tất cả đều tốt. Ngoài ra, tôi nên đề cập đến điều này dường như chỉ xảy ra trên máy tính dựa trên Intel Atom của tôi. Desktop PC dường như không có vấn đề gì.

Tôi biết chủ đề sử dụng lại nhóm chủ đề và theo mặc định Task sử dụng nhóm chủ đề. Và tôi biết rằng hồ bơi chủ đề thực sự dành cho các hoạt động ngắn ngủi. Nhưng tôi đã thử sử dụng các TaskCreationOptions.LongRunning, mà tôi nghĩ sẽ đẻ trứng một chủ đề chuyên dụng hơn là sử dụng hồ bơi thread, nhưng nó vẫn không hoạt động.

Câu hỏi: Điều gì làm cho Thread rất đặc biệt trong trường hợp này? Có điều gì đó về Thread mà làm cho nó phù hợp hơn cho các hoạt động IO?

Chỉnh sửa: Câu trả lời cho đến nay dường như giả định rằng tôi đang cố gắng sử dụng ThreadPool hoặc Task cho một quá trình không bao giờ kết thúc. Trong ứng dụng thực sự của tôi, đây không phải là trường hợp. Tôi chỉ sử dụng vòng lặp không bao giờ kết thúc trong đoạn mã trên để minh họa sự cố. Tôi thực sự cần biết lý do tại sao Thread hoạt động và ThreadPoolTask thì không. Thế nào là kỹ thuật khác nhau về họ mà có thể gây ra các giao tiếp nối tiếp để nấc cục?

+0

Tôi cho rằng đó là một câu hỏi ngớ ngẩn, nhưng bạn không cố gắng quản lý> = 25 chủ đề, phải không? – Jeff

+0

@ JeffN825, không, chỉ có 1 luồng cho mỗi cổng nối tiếp và tôi đang sử dụng tối đa 4 cổng nối tiếp. – Verax

+0

1 và 3 giống nhau. –

Trả lời

2

Về mặt triết học, có rất ít sự khác biệt giữa 1, 2 và 3 trong cách thực thi luồng. Tất cả đều chia sẻ cùng một ưu tiên thực thi mặc định trừ khi bạn ghi đè lên nó - theo lý thuyết, trình lập lịch trình chuỗi sẽ sử dụng cùng một chiến lược để lên lịch cho chúng. Họ tất cả đều ngồi vui vẻ quay vòng.

tôi nghi ngờ sự khác biệt lớn giữa các phương pháp là:

  1. chi phí cơ sở hạ tầng (chủ đề, bộ nhớ vv) quay lên để hỗ trợ threadpool của # 2 và # 3 tất cả trong số đó sẽ tranh cho đồng hồ timeslices với thực hiện của bạn vòng lặp.
  2. chi phí chuyển đổi ngữ cảnh chủ đề trên Atom ít cơ bắp hơn. Atom có ​​bộ nhớ cache nhỏ hơn, và các đường ống xử lý ngắn hơn. Các chủ đề đang chạy khác = nhiều chuyển mạch ngữ cảnh hơn, việc bán phá giá đường ống và giảm hiệu quả bộ nhớ cache của lệnh.

Từ cách sử dụng điểm chức năng của Phương pháp 2 và 3 có phần lạm dụng - ý định của bạn là không bao giờ thoát phương pháp. Các chiến lược này được tối ưu hóa cho các hoạt động hữu hạn, nguyên tử và thực thi không được bảo vệ phù hợp cho các nhiệm vụ cổng IO Hoàn thành như mạng không đồng bộ, hoạt động đĩa vv .. (Có thể là khả năng cho mã cổng nối tiếp của bạn?)

Tôi sẽ bỏ qua 2 & 3 trừ khi bạn quan tâm đến việc thích ứng với Async IO. Tập trung vào chủ đề - có vẻ như bạn đang muốn ngũ cốc tốt hơn, kiểm soát thực thi dự đoán mà không có chi phí cơ sở hạ tầng mà Threadpool mang lại.

+1

Đó là một cổng nối tiếp 9600 baud! Một ký tự mỗi mili giây. UART có bộ đệm phần cứng, trình điều khiển có bộ đệm. Nó gần như là ngoài niềm tin rằng một trong hai điểm này có thể là một vấn đề ở đây. –

+0

Máy tính xách tay chạy bằng nguyên tử Asus của tôi, (!), Sẽ vui vẻ chạy hai cổng nối tiếp ở 115Kbaud mà không gặp vấn đề gì. Nó không phải là phần cứng nói chung, (mặc dù, tất nhiên, hộp OP có thể là xấu). –

0

Có sự khác biệt nhỏ - mà gây ra timeouts:

  • Sử dụng Chủ đề một cách rõ ràng tạo ra một chủ đề mới khi Thread.start() là gọi - và nó đảm bảo rằng mã của bạn chạy thời điểm cụ thể.
  • Sử dụng ThreadPool đảm bảo rằng chuỗi sẽ được mở trong tương lai gần tương lai theo logic ThreadPool nội bộ. Bởi vì ThreadPool số bị giới hạn nên nên sử dụng nó cho các hoạt động chạy dài (hoặc vô hạn) .
  • Sử dụng tác vụ sẽ chỉ xác định rằng mã sẽ chạy. Hoặc trên một chuỗi khác hoặc thậm chí trên chuỗi chính và không đảm bảo rằng chuỗi sẽ chạy ngay lập tức hoặc các tác vụ khác nhau sẽ chạy trên các luồng khác nhau .

Và vì vậy nếu bạn muốn nhiệm vụ của mình bắt đầu nhanh, hãy luôn sử dụng Chủ đề. Cả Tasks và ThreadPool đều có một số "overhead overhead" bổ sung có thể gây ra sự chậm trễ nhỏ mà bạn nhận thấy.

Vì cả ThreadPool và tác vụ không có nghĩa là sẽ được sử dụng khi nhiệm vụ của bạn không bao giờ tồn tại, tôi đề nghị bạn sử dụng Thread.

1

Tôi nghi ngờ điều này xảy ra vì bạn đang đọc/ghi từ cổng COM. Nếu không có yếu tố đó, tất cả những điều này nên thực hiện giống nhau vì (nếu bạn kiểm tra) tất cả chúng đều chạy trong một luồng có mức độ ưu tiên Bình thường.

Có thể đọc trên I/O completion ports và nhóm chủ đề để xem liệu điều đó có thể giải thích hành vi kỳ quặc này hay không.

+0

Tôi nghĩ bạn chính xác. Cổng nối tiếp là thành phần chính của vấn đề này. Có thể bạn có thể xây dựng trên đề xuất cổng hoàn thành I/O? – Verax

+0

Xem thêm http://hi.baidu.com/jrckkyy/blog/item/401422527c131b070df3e37b.html để biết thêm thông tin về cách cổng I/O hoàn thành hoạt động. –

1

Có điều gì đó với mã của bạn, trình điều khiển hoặc phần cứng của bạn đã đặt hiệu suất cổng nối tiếp của bạn để 'ở cạnh' rằng nó đang ở trên bờ vực không hoạt động mọi lúc. Không nên có vấn đề bằng cách sử dụng một thread chuyên dụng hoặc threadpool, (mod. Sử dụng một thread threadpool để chặn trên một cổng nối tiếp đọc).

Hai cổng nối tiếp 9600 baud bạn có thể chạy bằng bàn tính, cung cấp các hạt và dây dẫn được bôi trơn tốt.

+0

Puh. Tôi có thể dễ dàng chạy hai cổng nối tiếp 9600 baud trên bàn tính gỉ. –

+0

Điều đó phù hợp với bạn. Bạn có thể có một bàn tính đa năng với hyperBeads. –