2013-04-28 33 views
5

Tôi đang viết một chương trình trong Qt, chạy 10 chuỗi công việc tính toán quỹ đạo của một đối tượng trong không gian. Họ cũng phải vẽ đường đi của vật thể. Tôi có một lớp "Body" bắt nguồn từ QGraphicsEllipseItem và nó có một QPainterPath trong đó. Lớp "Mô phỏng" có danh sách các chướng ngại vật trên thế giới, và cơ thể mô phỏng và chạy cho đến khi cơ thể va chạm với thứ gì đó. Mô phỏng chạy trong một luồng riêng biệt (được thực hiện với moveToThread, không phải bởi phân lớp QThread). Khi cơ thể va chạm, Mô phỏng phát ra một tín hiệu nói rằng nó kết thúc. Khi tất cả các chủ đề đã hoàn thành tôi muốn vẽ các đường dẫn (tôi làm điều đó bằng cách gọi một phương thức trong "Body" cho phép vẽ đường dẫn trong phương thức vẽ của nó).Vẽ từ nhiều chủ đề trong Qt

Đáng tiếc là tôi nhận được khẳng định lỗi:

ASSERT: "!unindexedItems.contains(item)" in file graphicsview\qgraphicsscenebsptreeindex.cpp, line 364 

Họ xảy ra dường như ngẫu nhiên. Tôi đã thử các loại kết nối khác nhau, không có kết quả.
Tôi đang bắt đầu chuỗi trong một vòng lặp.
Tôi đang sử dụng Qt 5.0

Trả lời

10

Nói chung, với Qt bạn không thể thực hiện bất kỳ hoạt động GUI nào bên ngoài luồng GUI (tức là chuỗi đang thực thi QApplication :: exec(), thường là chính ()).

Vì vậy, nếu bạn có nhiều chủ đề thao tác QGraphicsItems (đặc biệt là QGraphicsItems hiện là một phần của QGraphicsScene), đó có thể là nguyên nhân gây ra lỗi xác nhận của bạn. Đó là, khi thread GUI Qt đang làm mới cửa sổ của nó, nó đang đọc dữ liệu từ các đối tượng QGraphicsItem khác nhau như là một phần của các phép tính của nó, và hy vọng QGraphicsItems vẫn không đổi trong suốt thời gian hoạt động làm mới. Nếu một QGraphicsItem bị thay đổi (bởi một thread khác) trong khi refresh thường xuyên, thì các phép tính được thực hiện bởi thread chính có thể trở thành sai/hỏng và đôi khi gây ra lỗi xác nhận (và/hoặc các hành vi không mong muốn khác).

Nếu bạn thực sự cần phải sử dụng nhiều luồng, những gì bạn có thể cần làm là có các chủ đề thực hiện tất cả các tính toán của chúng trên cấu trúc dữ liệu riêng tư của chúng mà luồng GUI Qt không có quyền truy cập. Sau đó, khi các chủ đề đã tính toán kết quả của họ, họ sẽ gửi kết quả trở lại chủ đề GUI Qt (thông qua kết nối xếp hàng đợi hoặc QApplication :: postEvent()). Các chủ đề GUI sau đó có thể xem kết quả và sử dụng chúng để cập nhật các QGraphicsItems, vv; điều này sẽ "an toàn" vì bản cập nhật này không thể xảy ra ở giữa bản cập nhật cửa sổ.

Nếu điều đó nghe có vẻ quá nhiều công việc, thì bạn có thể xem xét chỉ làm mọi thứ trong luồng GUI; nó sẽ dễ dàng hơn và đơn giản hơn để làm cho mọi thứ hoạt động đáng tin cậy theo cách đó.

+0

"Lý tưởng nhất là không phải là đối tượng Qt, mặc dù có thể sử dụng một số lớp Qt nhất định nếu bạn rất cẩn thận"? Có một số lượng lớn các lớp có thể được sử dụng bên ngoài luồng GUI ...Nó sẽ là thú vị để có số, nhưng tôi sẽ nói rằng chỉ một phần nhỏ của Qt không được sử dụng bên ngoài thread GUI. –

+0

@LucaCarlon Quan điểm của tôi là nếu bạn sử dụng các lớp Qt, bạn cần xác minh rằng chúng an toàn để sử dụng, trong khi nếu bạn sử dụng một lớp không Qt, bạn có thể đảm bảo rằng nó sẽ không có bất kỳ tương tác với luồng GUI Qt. –

+0

Một số nguyên tắc cho Qt và đa luồng có tại đây: http://www.informit.com/articles/article.aspx?p=1405551&seqNum=4 –

3

Như đã đề cập bởi Jeremy, hiển thị Qt phải được thực hiện trên chuỗi chính.

Trong khi bạn có thể di chuyển tất cả sang chuỗi chính, bạn có thể đã chọn tạo riêng biệt cho hiệu quả, đặc biệt khi phát hiện xung đột có thể là bộ xử lý chuyên sâu. Cách tốt nhất để xử lý việc này là tách mô hình của các đối tượng và vật lý của chúng khỏi hiển thị của chúng, như bạn sẽ làm trong mô hình Model/View/Controller.

Tạo biểu diễn của các cá thể cơ thể không được lấy từ bất kỳ QGraphicsItem/Objects nào. Sau đó, chúng có thể thực hiện các phép tính trên các luồng riêng biệt và có các tín hiệu cho các đối tượng đồ họa đang chạy trong chuỗi chính, cập nhật biểu diễn đồ họa của mỗi cá thể, cho phép hiển thị các quỹ đạo thời gian thực.

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