2012-12-06 31 views
5

Biểu mẫu tôi đang cố gắng phát triển có một loạt 6 hộp hình ảnh và một mảng gồm 6 hình ảnh chết. Tôi có một nút mà khi nhấp vào cần phải tạo ra 6 chủ đề mà "cuộn" con xúc xắc, hiển thị mỗi hình ảnh cho một thời điểm. Vấn đề tôi gặp phải là tôi cần phải gọi một phương thức trong nút bấm sau khi xúc xắc đã được cuộn. Tôi có thể lấy xúc xắc để cuộn nhưng hộp tin nhắn được hiển thị ngay lập tức. Tôi đã thử một vài cách khác nhau và gặp nhiều lỗi khác nhau. Trong phiên bản không hoạt động bên dưới, chương trình bị treo. Tôi đã kiểm tra một tấn tài nguyên nhưng tôi chỉ không nắm bắt một số khái niệm như Đại biểu và Gọi tất cả những điều tốt. Mọi trợ giúp sẽ tuyệt vời! Đây là chương trình của tôiCác vấn đề với chuỗi chủ đề của tôi

namespace testDice 
{ 
    public partial class Form1 : Form 
    { 
     private Image[] imgAr; 
     private PictureBox[] picBoxAr; 
     private Random r; 
     private Thread[] tArray; 
     private ThreadStart tStart; 
     private delegate void setTheImages(); 

     public Form1() 
     { 
      InitializeComponent(); 
      setImageArray(); 
      setPicBoxAr(); 
     } 

     private void setImageArray() 
     { 
      imgAr = new Image[6]; 
      imgAr[0] = testDice.Properties.Resources.die6; 
      imgAr[1] = testDice.Properties.Resources.die1; 
      imgAr[2] = testDice.Properties.Resources.die2; 
      imgAr[3] = testDice.Properties.Resources.die3; 
      imgAr[4] = testDice.Properties.Resources.die4; 
      imgAr[5] = testDice.Properties.Resources.die5; 

     } 

     private void setPicBoxAr() 
     { 
      picBoxAr = new PictureBox[6]; 
      picBoxAr[0] = pictureBox1; 
      picBoxAr[1] = pictureBox2; 
      picBoxAr[2] = pictureBox3; 
      picBoxAr[3] = pictureBox4; 
      picBoxAr[4] = pictureBox5; 
      picBoxAr[5] = pictureBox6; 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      roll(); 

      //wait for threads to finish and update images--doesn't work 
      for (int n = 0; n < 6; n++) 
      { 
       while (tArray[n].IsAlive) 
       { 
        for (int i = 0; i < 6; i++) 
        { 
         this.picBoxAr[i].Update(); 
        } 
       } 
      } 

      MessageBox.Show("Each die has its own thread"); 
     } 

     private void roll() 
     { 
      this.tStart = new ThreadStart(RunAllDiceThreads); 
      this.tArray = new Thread[6]; 
      for (int i = 0; i < 6; i++) 
      { 
       this.tArray[i] = new Thread(tStart); 
       this.tArray[i].Start(); 
      } 
     } 

     private void RunAllDiceThreads() 
     { 
      int n = 0; 
      while (n < 50) 
      { 
       setImg(); 
       Thread.Sleep(50); 
       n++; 
      } 

      for (int i = 0; i < 6; i++) 
      { 
       if (tArray[i] != null) 
       { 
        tArray[i].Abort(); 
        tArray[i] = null; 
       } 
      } 
     }// end RunAllDiceThreads 

     private void setImg() 
     { 
      r = new Random(); 

      for (int i = 0; i < 6; i++) 
      { 
        if (this.picBoxAr[i].InvokeRequired) 
        { 
         setTheImages s = new setTheImages(setImg); 
         // parameter mismatch error here 
         //this.Invoke(s, new object[] { imgAr[r.Next(6)] }); 
         //Freezes here!! 
          this.Invoke(s); 
        } 
        else 
        { 
         this.picBoxAr[i].Image = imgAr[r.Next(6)]; 
        } 
      } 
     }//end setImg 

    }// end class Form1 
}//end namespace testDice 
+0

1. Toàn bộ chương trình đó trông giống như một vi phạm chủ đề an toàn lớn. 2. Tôi nghĩ bạn không cần chủ đề này. Thay vào đó, hãy sử dụng bộ hẹn giờ và cập nhật tất cả các con xúc xắc khi nó đánh dấu. – svick

+0

nhiệm vụ là sử dụng các chủ đề – Mox

+0

Bạn nên cân nhắc sử dụng TPL. – davenewza

Trả lời

2

Có vẻ như bạn đang bế tắc giữa yêu cầu đặt hình ảnh và cập nhật hộp hình ảnh.

Tôi khuyên bạn nên xem xét lại chương trình của mình một chút. Chương trình của bạn gần như có vẻ được xây dựng trên khái niệm rằng bạn đang lập mô hình một khuôn mẫu riêng lẻ với một chuỗi riêng lẻ. Phá vỡ trạng thái chết từ trạng thái của sợi chỉ. Ví dụ, bạn có thể muốn tạo một lớp Die có một trạng thái nhất định với nó, chẳng hạn như IsRolling, hoặc CurrentValue. Sử dụng và sửa đổi các đối tượng của lớp đó (và chỉ lớp đó) bên trong các vòng của bạn trong các chuỗi công việc của bạn. Bằng cách đó, bạn sẽ không phải gọi lại chuỗi giao diện người dùng của mình để cập nhật. Các phụ thuộc là sạch hơn rất nhiều theo cách đó. Bạn có thể muốn tạo một Timer trong chuỗi giao diện người dùng của bạn định kỳ kích hoạt (nói 10-30 lần một giây), đọc trạng thái của mỗi con xúc xắc và cập nhật hình ảnh theo cách đó. Đó là an toàn hơn rất nhiều về deadlocks bởi vì bạn không có bất kỳ phụ thuộc cyclic. Nó cũng có khả năng tạo ra một giao diện hấp dẫn hơn bởi vì hình ảnh chết của bạn sẽ cập nhật theo kiểu mượt mà, dễ dự đoán hơn.

Quy tắc khác ... Don't call Thread.Abort() (xem tham chiếu). Nói chung, an toàn hơn rất nhiều khi sử dụng thuộc tính của đối tượng Die và chỉ cần đọc từ đó để cập nhật giao diện người dùng của bạn.

+0

Cảm ơn các ý kiến. Tôi đã cố gắng để tạo ra một lớp xúc xắc trong phiên bản khác, nhưng nó sẽ không tốt lắm. Làm thế nào để đối tượng lớp xúc xắc cập nhật Hộp Hình ảnh? Nhưng vâng, tôi đang cố đi xuống con đường đó. – Mox

+0

Ah, nhưng thấy có bắt của bạn ... Nếu bạn nhấn mạnh vào đi xuống con đường của việc có Dice cập nhật các chủ đề giao diện người dùng, bạn mở cho mình lên đến phức tạp và deadlocks, giống như bạn đang có bây giờ. Chương trình bạn đăng trên thực tế là một ví dụ đơn giản, tốt để không theo đuổi kiến ​​trúc này.Rất nhiều lập trình viên chạy vào bẫy này - theo đuổi mục tiêu đóng gói mọi thứ được thực hiện bởi một đối tượng trong một chủ đề, khi thực sự nên làm gì để tách chức năng của giao diện người dùng khỏi hành vi của "mô hình", trong trường hợp này, Dice của bạn. http://en.wikipedia.org/wiki/Separation_of_concerns –

+0

Tôi nghe những gì bạn đang nói. Tôi đã đọc về MVC và cố gắng ghi nhớ điều đó. Tôi chỉ không chắc chắn làm thế nào để tách 2 khía cạnh của nhiệm vụ. Tôi cần phải cuộn từng con xúc xắc theo chủ đề riêng của nó. Mỗi luồng phải cập nhật hình ảnh của Hộp Ảnh. Khi các chủ đề được thực hiện, tôi cần phải chạy một phương pháp (hộp thư) ... – Mox

0

Bạn cần xóa MessageBox.Show("Each die has its own thread"); từ button1_Click.

Tạo thuộc tính để theo dõi số lượng chuỗi đã trả về. Khi nó nhấn 6 gọi MessageBox.Show("Each die has its own thread"); (có thể bạn sẽ muốn đặt cuộc gọi này theo phương thức riêng của nó và gọi phương thức đó).

Vấn đề của bạn là bạn đang bắt đầu chủ đề, sau đó trong khi chúng đang chạy hiển thị hộp thư thay vì đợi các chủ đề trả về.

-1

Nếu bạn có thể làm việc với phiên bản mới nhất của .Net Framework, tôi khuyên bạn nên sử dụng không gian tên System.Threading.Tasks. Điều tốt đẹp là nó đóng gói rất nhiều chi tiết đa luồng và làm cho mọi thứ sạch hơn. Đây là một ví dụ đơn giản.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace TasksExample 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      // holds all the tasks you're trying to run 
      List<Task> waitingTasks = new List<Task>(); 

      // a simple object to lock on 
      object padlock = new object(); 

      // simple shared value that each task can access 
      int sharedValue = 1; 

      // add each new task to the list above. The best way to create a task is to use the Task.Factory.StartNew() method. 
      // you can also use Task.Factory<RETURNVALUE>.StartNew() method to return a value from the task 
      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       // this makes sure that we don't enter a race condition when trying to access the 
       // shared value 
       lock (padlock) 
       { 
        // note how we don't need to explicitly pass the sharedValue to the task, it's automatically available 
        Console.WriteLine("I am thread 1 and the shared value is {0}.", sharedValue++); 
       } 
      })); 

      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       lock (padlock) 
       { 
        Console.WriteLine("I am thread 2 and the shared value is {0}.", sharedValue++); 
       } 
      })); 

      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       lock (padlock) 
       { 
        Console.WriteLine("I am thread 3 and the shared value is {0}.", sharedValue++); 
       } 
      })); 

      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       lock (padlock) 
       { 
        Console.WriteLine("I am thread 4 and the shared value is {0}.", sharedValue++); 
       } 
      })); 

      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       lock (padlock) 
       { 
        Console.WriteLine("I am thread 5 and the shared value is {0}.", sharedValue++); 
       } 
      })); 

      waitingTasks.Add(Task.Factory.StartNew(() => 
      { 
       lock (padlock) 
       { 
        Console.WriteLine("I am thread 6 and the shared value is {0}.", sharedValue++); 
       } 
      })); 


      // once you've spun up all the tasks, pass an array of the tasks to Task.WaitAll, and it will 
      // block until all tasks are complete 
      Task.WaitAll(waitingTasks.ToArray()); 

      Console.WriteLine("Hit any key to continue..."); 
      Console.ReadKey(true); 
     } 
    } 
} 

Tôi hy vọng điều này sẽ giúp và cho tôi biết nếu bạn cần thêm trợ giúp.

+0

Mã chính xác mà bạn đăng có liên quan đến câu hỏi này chính xác như thế nào? – svick

+0

Mục đích của tôi là tránh sử dụng mã luồng cũ hơn để ủng hộ không gian tên Tasks mới hơn, dễ sử dụng hơn. Nếu OP dự định sử dụng luồng để cập nhật giá trị của con xúc xắc, thì đây là cách dọn dẹp tốt hơn. Ngoài ra, nó làm nổi bật việc sử dụng từ khoá khóa để ngăn chặn bế tắc khi truy cập tài nguyên được chia sẻ. –

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