2012-01-25 34 views
8

Tôi đã tìm thấy một số câu hỏi liên quan đến vấn đề của mình nhưng vẫn không thể tự mình thực hiện điều này vì vậy tôi sẽ cố gắng hỏi tại đây. Tôi sẽ dán mã để tôi nghĩ rằng nó sẽ dễ dàng hơn để giải thích.Truyền dữ liệu giữa các chủ đề trong C#

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
     Thread thread = new Thread(new ThreadStart(StartCalculation)); 
     thread.Start(); 
    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 

    } 


    public void StartCalculation() 
    { 
     List<int> numbers = new List<int>(); 
     for (int i = 0; i <= 100; i++) 
     { 
      numbers.Add(i); 
      string textForLabel = i.ToString(); 
      label.SafeInvoke(d => d.Text = textForLabel); 
     } 

    } 
} 
  • Tôi muốn có một acces từ phương pháp StartCalculation mà bắt đầu trong chủ đề khác nhau. Tôi muốn truy cập danh sách int đó từ Form1 (10 phần tử sau 10 giây, 20 phần tử sau 20 giây và lâu hơn). Điều đó có thể không?
  • Tạo danh sách trong Form1() và sau đó thay đổi nó trong StartCalculation có thể? Cảm ơn câu trả lời :)

Edited cho Groo-/-

public partial class Form1 : Form 
{ 

List<int> list = new List<int>(); // list of int values from game's memory 

public Form1() 
{ 
    InitializeComponent(); 
    Thread thread = new Thread(new ThreadStart(refreshMemory)); 
    thread.Start(); 
    Thread thread2 = new Thread(new ThreadStart(checkMemory)); 
    thread2.Start(); 
} 

private void Form1_Load(object sender, EventArgs e) 
{ 
} 

public void refreshMemory() 
{   
    while (true) 
    { 
    // ... refresh game's memory and then, refresh list // 
    Thread.Sleep(100); 
    } 
} 

public void checkMemory() 
{ 

    while (true) 
    { 
    // eg. if (list[0] == 5) {game:: move_right()}// 
    Thread.Sleep(100); 
    } 

} 

} 

tôi là làm cho trò chơi bot. Tôi muốn nó đọc bộ nhớ của trò chơi trong một chủ đề khác (thay đổi danh sách bộ nhớ) và sau đó, với vài phương pháp khác (trong các chủ đề khác nhau), tôi muốn đọc từ danh sách đó và thực hiện các hành động trò chơi tùy thuộc vào giá trị bộ nhớ. Nó hoạt động (hoặc chỉ có vẻ là) nhưng nếu bạn nói nó có thể là không an toàn, tôi muốn làm cho nó an toàn.

Hy vọng tôi đã không đánh lừa bản thân bằng cách dán nó ở đây.

+6

Đây là một cuốn sách: [Threading in C#, Joseph Albahari] (http://www.albahari.com/threading/) – Sjoerd

+3

Vâng, cảm ơn bạn! Nhờ cuốn sách đó, nó đã được giải quyết ngay bây giờ :) – Patryk

+0

* "10 phần tử sau 10 giây, 20 phần tử sau 20 giây" * - tại sao những sự chậm trễ này? Điều gì xảy ra nếu chuỗi nền tạo ra các phần tử với tốc độ nhanh hơn? Hoặc nên làm việc này như là một nhà sản xuất/hàng đợi của người tiêu dùng, nhưng với một ngưỡng tối thiểu. 10 mục? – Groo

Trả lời

19

Bạn cần một số hình thức của một cơ chế đồng bộ để sửa đổi đối tượng giữa nhiều chủ đề. Nếu bạn không sử dụng một bộ sưu tập an toàn chủ đề chuyên biệt (chúng có sẵn trong .NET 4), bạn cần khóa bằng cách sử dụng một màn hình.

Thông thường, một loại bộ sưu tập phù hợp hơn cho các mô hình sản xuất/tiêu dùng là một (một bộ sưu tập FIFO) Queue, thay vì một List:

Plain Queue với rõ ràng khóa

private readonly object _lock = new object(); 
private readonly Queue<Item> _queue = new Queue<Item>(); 
private readonly AutoResetEvent _signal = new AutoResetEvent(); 

void ProducerThread() 
{ 
    while (ShouldRun) 
    { 
     Item item = GetNextItem(); 

     // you need to make sure only 
     // one thread can access the list 
     // at a time 
     lock (_lock) 
     { 
      _queue.Enqueue(item); 
     } 

     // notify the waiting thread 
     _signal.Set(); 
    } 

} 

Và trong chuỗi tiêu thụ, bạn cần tìm nạp mục và xử lý nó:

void ConsumerThread() 
{ 
    while (ShouldRun) 
    { 
     // wait to be notified 
     _signal.Wait(); 

     Item item = null; 

     do 
     { 
      item = null; 

      // fetch the item, 
      // but only lock shortly 
      lock (_lock) 
      { 
       if (_queue.Count > 0) 
        item = _queue.Dequeue(item); 
      } 

      if (item != null) 
      { 
       // do stuff 
      }    
     } 
     while (item != null); // loop until there are items to collect 
    } 
} 

Bắt đầu với NET 4, có một bộ sưu tập ConcurrentQueue<T>, một FIFO thread-safe, mà loại bỏ sự cần thiết phải khóa khi truy cập nó và đơn giản hóa các mã:

ConcurrentQueue

private readonly ConcurrentQueue<Item> _queue = new ConcurrentQueue<Item>(); 

void ProducerThread() 
{ 
    while (ShouldRun) 
    { 
     Item item = GetNextItem(); 
     _queue.Enqueue(item); 
     _signal.Set(); 
    } 

} 

void ConsumerThread() 
{ 
    while (ShouldRun) 
    { 
     _signal.Wait(); 

     Item item = null; 
     while (_queue.TryDequeue(out item)) 
     { 
      // do stuff 
     } 
    } 
} 

Cuối cùng, nếu bạn chỉ muốn chuỗi tiêu thụ của bạn nhận được các mục theo từng phần theo định kỳ, bạn sẽ thay đổi mục này thành:

ConcurrentQueue with threshold (10 sec. hoặc 10 mặt hàng)

private readonly ConcurrentQueue<Item> _queue = new ConcurrentQueue<Item>(); 

void ProducerThread() 
{ 
    while (ShouldRun) 
    { 
     Item item = GetNextItem(); 
     _queue.Enqueue(item); 

     // more than 10 items? panic! 
     // notify consumer immediately 

     if (_queue.Count >= 10) 
      _signal.Set(); 
    } 

} 

void ConsumerThread() 
{ 
    while (ShouldRun) 
    { 
     // wait for a signal, OR until 
     // 10 seconds elapses 
     _signal.Wait(TimeSpan.FromSeconds(10)); 

     Item item = null; 
     while (_queue.TryDequeue(out item)) 
     { 
      // do stuff 
     } 
    } 
} 

mô hình này là rất hữu ích mà nó rất hay để trừu tượng nó thành một lớp chung mà các đại biểu xuất và tiêu thụ để mã bên ngoài. Nó sẽ là một bài tập tốt để làm cho nó chung chung.

Bạn cũng sẽ cần phương thức Stop có thể sẽ đặt cờ volatile bool cho biết đã đến lúc dừng và sau đó đặt tín hiệu để hủy tạm dừng người tiêu dùng và cho phép kết thúc. Tôi sẽ để điều này cho bạn như một bài tập.

+0

Tôi chỉ đọc với vài chủ đề từ một đối tượng và nếu tôi muốn sửa đổi, tôi đang lập kế hoạch cho phép 1 chủ đề sửa đổi 1 đối tượng. Là nó ok mà không có công cụ ur sau đó? – Patryk

+1

Nếu một luồng khác đang ghi vào một đối tượng không an toàn với luồng, thì bạn cần khóa cả đọc và ghi **. Hiệu suất-khôn ngoan, nếu bạn có nhiều chủ đề đọc và chỉ có một văn bản duy nhất, bạn có thể xem xét việc sử dụng một [ReaderWriterLockSlim] (http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx) , được thiết kế để cho phép thông lượng cao hơn cho nhiều người đọc đồng thời. Nhưng đối với một số lượng thấp người đọc nó vẫn có thể chậm hơn so với một khóa thông thường, và hơi phức tạp hơn để thực hiện (vì vậy tôi sẽ không xem xét nó tại thời điểm này). – Groo

+1

Vì vậy, có, bạn cần một chủ đề an toàn chủ đề nếu bạn muốn sửa đổi nó từ một chủ đề khác nhau. Nếu đó là một danh sách, bạn rất có thể cần một 'ConcurrentQueue'. Nếu không, hãy đăng một số chi tiết bổ sung. – Groo

0

trong trường hợp này sử dụng

label.Invoke(..., textForLabel) 
Các vấn đề liên quan