2009-07-18 40 views
8

Tôi từng nghĩ tôi là một người thông minh hợp lý.
"hướng dẫn lập trình luồng" của Apple, đã phá vỡ bản ngã của tôi để duy trì sự lừa dối bản thân.Vòng lặp Objective-C để dừng và khởi động lại phương thức?

Tôi có một phương pháp tôi muốn chạy liên tục trên chuỗi phụ, trong ví dụ bên dưới, tôi đã gọi đây là doStuff:
Tôi muốn có thể dừng liên tục và bắt đầu gọi lặp lại phương thức này.

mã bắt đầu chuỗi.
nếu giá trị stuffToDo boolean là đúng,
sau đó nó gọi doStuff:
khác
nó có một chút nghỉ ngơi.
sau đó nó lặp lại cho đến khi tôi yêu cầu dừng lại

Mã hiện tại của tôi dường như lãng phí, vì nó luôn kiểm tra 'stuffToDo' ngay cả khi không có gì để làm.

Tôi có thể loại bỏ stuffToDo và chỉ sinh đẻ và hủy chuỗi khi cần.
Điều này cũng có vẻ lãng phí, và có nghĩa là tôi sẽ cần phải cẩn thận không vô tình đẻ trứng một sợi mới khi tôi đã có một chạy.

Tôi chắc chắn rằng câu trả lời cho việc giải quyết có hiệu quả tình trạng khó khăn của tôi có thể được tìm thấy ở đâu đó trong "quản lý vòng lặp chạy" trong phần "Các luồng hướng dẫn lập trình" của Apple
có lẽ nó liên quan đến các nguồn đầu vào tùy chỉnh

Nhưng tôi thực sự tìm tài liệu này đầy thử thách.
Nó giống như là tài liệu này đang sinh ra quá nhiều luồng trong não và việc tính toán sẽ dừng lại.

enum eRenderThreadMode 
{ 
    render_not_started, 
    render_run, 
    render_cancel, 
    render_finished 
}; 


- (IBAction) startThread:(id)sender 
{ 
    self.renderThreadMode = render_run; 
    label.text = @"doing stuff"; 
    [NSThread detachNewThreadSelector:@selector(keepDoingStuff) toTarget:self withObject:nil]; 

} 

- (void)keepDoingStuff 
{ 
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; 

    while (renderThreadMode == render_run) 
    { 
     if(stuffToDo) 
     { 
      [self doStuff]; 
     } 
     else 
     { 
      [NSThread sleepForTimeInterval:kLittleRest]; 
     } 
    } 
    self.renderThreadMode = render_finished; 
    [pool release]; 
} 


- (IBAction)stopThread:(id)sender 
{ 
    self.renderThreadMode = render_stop; 

    while (self.renderThreadMode == render_cancel) 
    { 
     [NSThread sleepForTimeInterval:kLittleRest]; 
    } 
} 

Trả lời

7

Bạn có thể sử dụng đối tượng đồng bộ hóa mà chuỗi phụ của bạn được bật. This Apple page cho biết có một cơ sở được gọi là Điều kiện có thể làm những gì bạn muốn. Sử dụng một điều kiện hoặc đối tượng đồng bộ hóa tương tự sẽ cho phép chủ đề của bạn chỉ được đánh thức khi có công việc được thực hiện (hoặc khi đến lúc chuỗi bị chết).

+0

Đồng ý. Sử dụng NSConditionLock. Đây là một cấu trúc luồng chuẩn. –

+0

cảm ơn bạn, điều này có vẻ như nó sẽ làm chính xác những gì tôi muốn –

+0

Tôi đã sử dụng NSCondition, như aem được đề xuất, thay vì NSConditionLock. Bạn có thực sự có nghĩa là ConditionLock thay vì điều kiện đó? Nếu có, bạn sẽ hình dung ra điều này bằng cách sử dụng NSConditionLock như thế nào. Tôi đã không làm việc với các chủ đề c mục tiêu trước đây và tôi thích nghe về các cách tiếp cận khác nhau. –

7

Vâng, bạn đúng là bạn muốn sử dụng một runloop, những gì bạn đang thiếu là làm thế nào để thiết lập này tất cả lên. Tôi sẽ sửa đổi bài viết của bạn và giải thích những gì đang xảy ra. Đừng lo lắng nếu nó intimidates bạn, nó là khó khăn và có một số vấn đề bạn chỉ tìm hiểu về kinh nghiệm

- (IBAction) startThread:(id)sender 
{ 
    self.renderThreadMode = render_run; 
    label.text = @"doing stuff"; 
    self.backgroundThread = [[NSThread alloc] initWithTarget:self selector:@selector(keepDoingStuff) object:nil]; 
    [self.backgroundThread start];  
} 

//Okay, this is where we start changing stuff 
- (void)keepDoingStuff 
{ 
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

     //A runloop with no sources returns immediately from runMode:beforeDate: 
     //That will wake up the loop and chew CPU. Add a dummy source to prevent 
     //it. 

     NSRunLoop *runLopp = [NSRunLoop currentRunLoop]; 

     NSMachPort *dummyPort = [[NSMachPort alloc] init]; 
     [runLoop addPort:dummyPort forMode:NSDefaultRunLoopMode]; 
     [dummyPort release]; 
     [pool release]; 

     while (1) 
     { 
       NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; 
       [runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; 
       [loopPool drain]; 
     } 
} 

Được rồi, vì vậy vào thời điểm này, bạn nên nhìn vào đoạn code trên và suy nghĩ "Vâng, đó là có thể là một chủ đề ngủ đẹp, nhưng nó không làm gì cả. Và đó là sự thật, nhưng vì nó có một runloop hoạt động, chúng ta có thể làm bất cứ điều gì đó là runloop dựa vào nó, bao gồm performSelector: onThread: withObject: waitUntilDone:

- (void) doStuffOnBackgroundThread 
{ 
    [self performSelector:@selector(doStff) onThread:self.backgroundThread withObject:nil waitUntilDone:NO]; 
} 

Khi bạn gọi phương thức trên trên chủ đề chính của bạn (hoặc bất kỳ chủ đề nào khác), nó sẽ sắp xếp lại các đối số khác nhau và enqueue runloop của specif ied thread, đánh thức nó khi cần thiết. Trong trường hợp này sẽ gây self.backgroundThread để wakeup từ runMode: beforeDate :, execute-doStuff, sau đó chu kỳ trở lại aroound vòng lặp và quay trở lại ngủ chờ trong runMode: beforeDate :.Nếu bạn muốn có thể xé sợi chỉ, bạn có thể thiết lập một biến trong vòng lặp giống như bạn đã có trong mã của mình, mặc dù nhớ chuỗi sẽ biến mất nếu nó đang ngủ trừ khi bạn đánh thức nó, vì vậy nó có thể đóng gói tốt nhất rằng trong một phương thức thiết lập biến điều khiển thông qua một performSelector: onThread: withObject: waitUntilDone :, như một dấu cộng, điều đó có nghĩa là biến sẽ chỉ được thiết lập từ luồng nền để đơn giản hoá các vấn đề đồng bộ hóa.

Được rồi, vì vậy tôi nghĩ rằng giải quyết vấn đề của bạn, do đó, thời gian để thực hiện các plug bắt buộc: Bạn có chắc bạn muốn làm điều này với chủ đề? NSOperation và NSOperationQueue có thể là một giải pháp đơn giản hơn nhiều mà sẽ chăm sóc tất cả các vấn đề luồng cho bạn nếu tất cả những gì bạn cần làm là thỉnh thoảng enqueue một số dữ liệu để xử lý. Họ sẽ lên kế hoạch làm việc, quản lý các phụ thuộc, và xây dựng/phá bỏ các chủ đề cũng như chăm sóc tất cả các công cụ đánh thức/ngủ runloop.

+0

cảm ơn câu trả lời chi tiết tuyệt vời. Trong đã được tắt bằng cách sử dụng NSOperation, bởi vì tôi đã được ấn tượng NSOperation được thiết kế để xử lý một số lượng hữu hạn của công việc, nơi như tôi muốn bắt đầu một sợi và giữ cho nó chạy trong một thời gian vô hạn, (tối thiểu 2 giây, tối đa đến pin chạy phẳng?) vì vậy tôi biết tôi không chắc chắn rằng tôi cần phải sử dụng đề trên NSOperation, nó chỉ là dựa trên một ý nghĩa mơ hồ trong đó cảm thấy giá trị nhất điều tra –

+0

Bạn có thể làm một trong hai. Một NSOperationQueue sẽ tiếp tục chạy cho đến khi nó trống, nhưng bạn có thể giữ nó xung quanh và ném nhiều NSOperations vào nó bất cứ lúc nào và có nó xử lý chúng. –

+0

Cảm ơn Louis, một vài câu hỏi về phía trên, nơi runLoop đến từ đâu? cũng trong trường hợp của tôi khi thread đang hoạt động, tôi muốn nó tiếp tục gọi doStuff: nhanh nhất có thể mà không có sự can thiệp của tôi, vì vậy tôi có thể thay đổi cấu trúc để tôi gọi một cái gì đó như: [self performSelector: @selector (doAsMuchStuffAsYouCanUntilItellYouToStop) onThread: self.backgroundThread withObject: nil waitUntilDone: NO]; –

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