2012-05-06 38 views
12

Làm cách nào để tạm dừng/tiếp tục một chuỗi? Khi tôi Join() một chuỗi, tôi không thể khởi động lại. Vì vậy, làm thế nào tôi có thể bắt đầu một sợi và làm cho nó tạm dừng bất cứ khi nào nút 'tạm dừng' được nhấn, và tiếp tục nó khi nút tiếp tục được nhấn?cách tạm dừng/tiếp tục một chủ đề

Điều duy nhất mà chuỗi này làm là hiển thị một số văn bản ngẫu nhiên trong điều khiển nhãn.

+1

Bạn có thể thêm mã của mình trong câu hỏi – Adil

+0

Không có mã nào vào lúc này. Tôi vẫn đang nghĩ cách thực hiện dự án này trong đầu mình. Tất cả tôi có thể nói với bạn rằng tôi biết từ kinh nghiệm với công việc của tôi với luồng, một khi một sợi được nối với chủ đề chính, không có cách nào tôi có thể tiếp tục/khởi động lại nó. – Yustme

Trả lời

16

Có lẽ ManualResetEvent là một lựa chọn tốt. Ví dụ ngắn:

private static EventWaitHandle waitHandle = new ManualResetEvent(initialState: true); 

// Main thread 
public void OnPauseClick(...) { 
    waitHandle.Reset(); 
} 

public void OnResumeClick(...) { 
    waitHandle.Set(); 
} 

// Worker thread 
public void DoSth() { 
    while (true) { 
    // show some random text in a label control (btw. you have to 
    // dispatch the action onto the main thread) 
    waitHandle.WaitOne(); // waits for the signal to be set 
    } 
} 
+0

Không hoạt động trong VirtualBox XP.Bạn không biết tại sao? – zionpi

+0

Tôi đã bị cám dỗ để downvote cho việc sử dụng một [_reserved keyword_] (https://msdn.microsoft.com/en-us/library/x53a06bb.aspx) như là một tên biến, nhưng giải pháp làm việc hoàn toàn quá tốt cho tôi để troll :-) – MDMoore313

+0

Tôi không xác định sự kiện (♡ Rx ♡), vì vậy tôi không biết rằng 'sự kiện' là từ khóa :-) –

5

tôi có thể đề nghị bạn đọc Threading in C#, by Joe Albahari, đặc biệt là Suspend and Resume phần:

Một thread có thể bị đình chỉ một cách rõ ràng và tiếp tục thông qua các phương pháp phản Thread.Suspend và Thread.Resume. Cơ chế này hoàn toàn tách biệt với cơ chế chặn. Cả hai hệ thống đều độc lập và hoạt động song song.

Chủ đề có thể tự treo hoặc một chuỗi khác. Việc gọi các kết quả Tạm dừng trong luồng nhanh chóng vào trạng thái SuspendRequested, sau đó khi đạt đến một điểm an toàn để thu gom rác, nó sẽ đi vào trạng thái Tạm dừng. Từ đó, nó có thể được nối lại chỉ qua một luồng khác gọi phương thức Resume của nó. Tiếp tục sẽ chỉ hoạt động trên một chuỗi bị treo, không phải là một chuỗi bị chặn.

Từ .NET 2.0, Tạm dừng và Tiếp tục không được chấp nhận, việc sử dụng chúng không được khuyến khích vì sự nguy hiểm vốn có trong việc tự ý treo một chuỗi khác. Nếu một chuỗi giữ một khóa trên một tài nguyên quan trọng bị đình chỉ, toàn bộ ứng dụng (hoặc máy tính) có thể bế tắc. Điều này là nguy hiểm hơn nhiều so với gọi Abort - mà kết quả trong bất kỳ khóa như vậy được phát hành (ít nhất về mặt lý thuyết) bởi đức hạnh của mã trong khối cuối cùng.

SuspendRequested state

+0

Trích dẫn khối của bạn tạo sự khác biệt giữa một chuỗi bị treo so với một chuỗi bị chặn, nhưng biểu đồ dường như không tạo nên sự khác biệt này. Điều này có chủ ý không? – Tung

+0

@gliderkite, xem câu trả lời của tôi cho Adil về việc hiển thị mã. – Yustme

+0

@Tung Một chủ đề được coi là bị chặn khi việc thực hiện của nó bị tạm dừng vì một số lý do, chẳng hạn như khi Ngủ hoặc đợi người khác kết thúc qua Tham gia hoặc EndInvoke. Trong mã: 'bool blocked = (someThread.ThreadState & ThreadState.WaitSleepJoin)! = 0;'. Vậy tại sao không có sự khác biệt trong biểu đồ. Xem [this] (http://www.albahari.com/threading/part2.aspx#_Blocking). – gliderkite

2

Không phải là ý tưởng tốt nhất để tạm dừng và tiếp tục thủ công chủ đề. Tuy nhiên, bạn có thể dễ dàng mô phỏng hành vi này bằng cách sử dụng nguyên gốc đồng bộ hóa chủ đề (như ManualResetEvent)

Hãy xem this question, bạn có thể thấy hữu ích.

Nhưng tôi tin rằng bạn có thể dễ dàng đạt được mục tiêu 'hiển thị văn bản ngẫu nhiên trong điều khiển nhãn' trên cơ sở thời gian bằng cách sử dụng bộ hẹn giờ.

Dưới đây là một ví dụ nhanh sử dụng DispatcherTimer

var timer = new DispatcherTimer(); 
timer.Tick += (s, e) => Label.Text = GetRandomText(); 
timer.Interval = TimeSpan.FromMilliseconds(500); 
timer.Start(); 

Bạn có thể tạm dừng nó bằng cách gọi timer.Stop() và sau đó timer.Start() một lần nữa để tiếp tục.

+0

Xin chào, điều này có vẻ hay, tôi có thể đặt mã này vào một chuỗi riêng biệt không ? Vì tôi không muốn chặn luồng GUI. – Yustme

+0

@Yustme: AFAIK mã của 'DispatcherTimer' thực thi trên luồng GUI. Nếu bạn muốn một thread riêng biệt sử dụng 'System.Threading.Timer'. – Tudor

+0

Tudor là đúng, vì vậy nếu bạn có một số mã 'nặng' cần được thực hiện trên các con tim của bộ đếm thời gian, hãy sử dụng chuỗi riêng biệt. Nhưng nếu bạn chỉ cần cập nhật khối văn bản, sử dụng 'DispatcherTimer' là tốt và sẽ không chặn giao diện người dùng của bạn. –

1

Đây là hai cách phù hợp với tôi. Cả hai giả định rằng chuỗi công nhân có vòng lặp xử lý riêng của nó.

  1. Có thread gọi một callback để yêu cầu sự cho phép để tiếp tục đi
  2. Có phụ huynh gọi một phương thức trên lớp của chủ đề để báo hiệu nó

Ví dụ giao diện điều khiển ứng dụng dưới đây cho thấy cả hai phương pháp, sử dụng một cuộc gọi lại để tạm dừng/tiếp tục và một phương thức nhân viên dừng lại.Một ưu điểm khác của phương thức gọi lại là nó cũng thuận tiện cho việc trả về các cập nhật trạng thái trong khi nó đang kiểm tra sự cho phép để tiếp tục.

using System; 
using System.Threading; 

namespace ConsoleApplication7 
{ 
    class Program 
    { 
     static bool keepGoing; 
     static void Main(string[] args) 
     { 
      keepGoing = true; 
      Worker worker = new Worker(new KeepGoingDelegate(KeepGoing)); 
      Thread thread = new Thread(worker.DoWork); 
      thread.IsBackground = true; 
      thread.Start(); 

      while (thread.ThreadState != ThreadState.Stopped) 
      { 
       switch (Console.ReadKey(true).KeyChar) 
       { 
        case 'p': 
         keepGoing = false; 
         break; 
        case 'w': 
         keepGoing = true; 
         break; 
        case 's': 
         worker.Stop(); 
         break; 
       } 
       Thread.Sleep(100); 
      } 
      Console.WriteLine("Done"); 
      Console.ReadKey(); 
     } 

     static bool KeepGoing() 
     { 
      return keepGoing; 
     } 
    } 

    public delegate bool KeepGoingDelegate(); 
    public class Worker 
    { 
     bool stop = false; 
     KeepGoingDelegate KeepGoingCallback; 
     public Worker(KeepGoingDelegate callbackArg) 
     { 
      KeepGoingCallback = callbackArg; 
     } 

     public void DoWork() 
     { 
      while (!stop) 
      { 
       Console.Write(KeepGoingCallback()?"\rWorking":"\rPaused "); 

       Thread.Sleep(100); 
      } 
      Console.WriteLine("\nStopped"); 
     } 

     public void Stop() 
     { 
      stop = true; 
     } 
    } 
} 
+0

Xin chào, vì cuộc sống của tôi, tôi gặp khó khăn khi hiểu các đại biểu. Tôi có thể tìm ra cách để ngăn chặn các chủ đề, nhưng tôi không hiểu làm thế nào bạn đang khởi động lại nó? – Zev

+0

@Zev - một ủy quyền giữ chỗ cho một phương thức, để bạn có thể chuyển nó vào một thể hiện của một lớp khác để nó có thể thực thi nó. Trong ví dụ của tôi, cha mẹ chuyển phương thức 'KeepGoing()' vào công nhân, mà nó định kỳ gọi để kiểm tra lại với phụ huynh để xem nó có tiếp tục không. Chuỗi công nhân không khởi động lại mỗi lần - nó được khởi chạy một lần và tiếp tục cho đến khi nó nhận tín hiệu dừng. –

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