2009-12-05 17 views
20

Tôi đã trải qua this SO question nhưng đối tượng đó không giúp ích gì.InvalidOperationException - đối tượng hiện đang được sử dụng ở nơi khác

Trường hợp ở đây khác. Tôi đang sử dụng Backgroundworkers. 1st BackgroundWorker bắt đầu hoạt động vào hình ảnh đầu vào của người dùng và bên firstbackgroundworker_runworkercompleted() Tôi đang sử dụng gọi 3 backgroundworkers khác

algo1backgroundworker.RunWorkerAsync(); 
algo2backgroundworker.RunWorkerAsync(); 
algo3backgroundworker.RunWorkerAsync(); 

đây là mã cho mỗi:

algo1backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

algo2backgroundworker_DoWork() 
{ 
Image img = this.picturebox.Image; 
imgclone = img.clone(); 
//operate on imgclone and output it 
} 

hoạt động tương tự được thực hiện trong khác algo * backgrougrondworker_doWork().

Bây giờ SOMETIMES tôi nhận được "InvalidOperationException - đối tượng hiện đang được sử dụng ở nơi khác". Nó rất tùy ý. Tôi somtimes nhận được điều này trong algo1backgroundworker_DoWork và đôi khi trong algo2backgroundworker_DoWork và đôi khi trong Application.Run (new myWindowsForm());

Tôi không biết đầu mối gì đang xảy ra.

Trả lời

39

Có một khóa bên trong GDI + để ngăn hai luồng truy cập một bitmap cùng một lúc. Đây không phải là một loại khóa chặn, nó là một "lập trình viên đã làm điều gì đó sai, tôi sẽ ném một ngoại lệ" loại khóa. Chủ đề của bạn là ném bom vì bạn đang sao chép hình ảnh (== truy cập bitmap) trong tất cả các chuỗi. Chủ đề giao diện người dùng của bạn là đánh bom vì nó đang cố gắng vẽ bitmap (== truy cập bitmap) cùng lúc một chuỗi đang nhân bản nó.

Bạn cần hạn chế quyền truy cập vào bitmap chỉ với một chuỗi. Sao chép các hình ảnh trong chuỗi giao diện người dùng trước khi bạn bắt đầu BGW, mỗi BGW cần bản sao của hình ảnh đó. Cập nhật thuộc tính Hình ảnh của PB trong sự kiện RunWorkerCompleted.Bạn sẽ mất một số đồng thời theo cách này nhưng điều đó là không thể tránh khỏi.

19

Vì vậy, có vẻ như BackgroundWorkers của bạn đang cố truy cập cùng một thành phần Windows Forms cùng một lúc. Điều này sẽ giải thích tại sao thất bại là ngẫu nhiên.

Bạn sẽ cần phải đảm bảo điều này không xảy ra bằng cách sử dụng một lock, có lẽ như vậy:

 private object lockObject = new object(); 

    algo1backgroundworker_DoWork() 
    { 
     Image imgclone; 
     lock (lockObject) 
     { 
     Image img = this.picturebox.Image; 
     imgclone = img.clone(); 
     } 
     //operate on imgclone and output it 
    } 

Lưu ý rằng tôi chắc chắn rằng imgclone là địa phương để phương pháp này - bạn chắc chắn không muốn chia sẻ nó trên tất cả các phương pháp!

Mặt khác cùng một ví dụ lockObject được sử dụng bởi tất cả các phương pháp. Khi phương thức BackgroundWorker nhập phần lock{} của mình, một số khác đến điểm đó sẽ bị chặn. Vì vậy, điều quan trọng là phải đảm bảo rằng mã trong phần bị khóa là nhanh.

Khi bạn đến "đầu ra" hình ảnh đã xử lý của bạn, hãy cẩn thận để đảm bảo rằng bạn không thực hiện cập nhật qua luồng cho giao diện người dùng. Kiểm tra this post để biết cách ngăn chặn điều đó.

1

Trong các cửa sổ biểu mẫu không chỉ bạn chỉ nên truy cập các điều khiển từ một chủ đề duy nhất nhưng chủ đề đó phải là chủ đề ứng dụng chính, luồng tạo điều khiển.

Điều này có nghĩa là trong DoWork bạn không nên truy cập bất kỳ điều khiển nào (không sử dụng Control.Invoke). Vì vậy, ở đây bạn sẽ gọi RunWorkerAsync đi qua trong bản sao hình ảnh của bạn. Bên trong xử lý sự kiện DoWork, bạn có thể trích xuất tham số từ DoWorkEventArgs.Argument.

Chỉ trình xử lý sự kiện ProgressChanged và RunWorkerCompleted mới tương tác với GUI.

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