2013-10-09 23 views
2

我想要实现使用NSThread多NSThreads同步

我有一个主线程和三(3)的WorkerThread T1,T2,T3以下任务。所有这些从主线程同时开始,主线程有一个int size变量。现在我想在某种程度上,他们三个同步线程,当我的上述每个线程将执行,它将打印如下:

//在主线程

- (void) mainFunction{ 
    size = 0; 

    NSThread* T1 = [[NSThread alloc] initWithTarget:self 
              selector:@selector(workerThread:) 
              object:@"T1"]; 
    [T1 start]; 


    NSThread* T2 = [[NSThread alloc] initWithTarget:self 
              selector:@selector(workerThread:) 
              object:@"T2"]; 
    [T2 start]; 

    NSThread* T3 = [[NSThread alloc] initWithTarget:self 
              selector:@selector(workerThread:) 
              object:@"T3"]; 
    [T3 start]; 


} 

//工作者线程

- (void) workerThread:(id)obj{ 

    size++; 
    NSLog(@"Thread:%@--------Size:%d,obj,size) 

} 

我想下面的输出:

Thread:T1-------Size:1 
Thread:T2-------Size:2 
Thread:T3-------Size:3 

Thread:T1-------Size:4 
Thread:T2-------Size:5 
Thread:T3-------Size:6 

Thread:T1-------Size:7 
Thread:T2-------Size:8 
Thread:T3-------Size:9 

并返回控制权交还给麦n个线程时size=10

+0

您明确使用线程而不是GCD或NSOperationQueues的任何特定原因? – JonahGabriel

回答

3

一对夫妇的想法:

  1. 你说 “控制权返回给主线程时大小= 10”。这不太合理。主线程永远不会“失控”(因为这些线程同时发生)。也许你想在这种情况发生时在主线上发生什么事情?

  2. 你没有workerThread方法做任何循环,因此,如你所写,每个线程都会这样做,然后退出。您可能需要在此添加某种形式的循环。

  3. 即使您添加了循环,您希望的输出表明您正在假设将发生的特定操作序列,即这三个线程将按顺序运行(但您没有这样的保证)。如果你需要这种行为,你会建立一系列的信号灯,通过它你可以让一个线程等待一个信号被另一个线程发送。

  4. 从不同线程更新变量时应该小心。请参阅“线程编程指南”的Synchronization部分。处理像您的计数器这样的基本数据类型时会简化(只需确保将其声明为atomic)。但在更实质性的情况下,您会想要采用一些同步技术,例如@synchronized,锁定,专用定制串行队列等。

  5. 通常,如果您使用的是线程(但如果使用队列则不需要) ,你的线程应该是creating an autorelease pool

无论如何,与这些观察之外,你可能会有诸如以下,其中(一)具有@autoreleasepool; (b)循环;和(c)使用锁,以确保各个线程同步它们与size变量相互作用:

- (void) workerThread:(id)obj 
{ 
    @autoreleasepool { 

     BOOL done = NO; 

     while (!done) { 

      [self.lock lock]; 

      if (size < 9) { 
       size++; 
       NSLog(@"Thread:%@--------Size:%d", obj, size); 
      } 
      else 
      { 
       done = YES; 
      } 

      [self.lock unlock]; 

      // perhaps you're doing something time consuming here... 
     } 
    } 
} 

这里假设你有NSLock属性,称为lock

@property (nonatomic, strong) NSLock *lock; 

您之前创建开始你的线程测试:

- (void) threadTest 
{ 
    size = 0; 

    self.lock = [[NSLock alloc] init]; 

    NSThread* T1 = [[NSThread alloc] initWithTarget:self selector:@selector(workerThread:) object:@"T1"]; 
    [T1 start]; 

    NSThread* T2 = [[NSThread alloc] initWithTarget:self selector:@selector(workerThread:) object:@"T2"]; 
    [T2 start]; 

    NSThread* T3 = [[NSThread alloc] initWithTarget:self selector:@selector(workerThread:) object:@"T3"]; 
    [T3 start]; 
} 

说完所有这些之后,你就开始使用“return control back to the主线程“。正如我前面所说,真的没有必要这样做,因为在你的例子中,你的应用程序的主线程永远不会控制

为了控制在不同线程上发生的任务之间的关系,我可能会建议使用GCD或操作队列。它们更易于使用,并具有更好的机制来控制各种任务/操作之间的依赖关系(请参阅Concurrency Programming Guide)。

例如,考虑基于操作相当于你上面workerThread方法(相同的,但不需要自动释放池):

- (void) operationMethod:(id)obj 
{ 
    BOOL done = NO; 

    while (!done) { 

     [self.lock lock]; 

     if (size < 9) { 
      size++; 
      NSLog(@"Operation:%@--------Size:%d", obj, size); 
     } 
     else 
     { 
      done = YES; 
     } 

     [self.lock unlock]; 

     // perhaps you're doing something time consuming here... 
    } 
} 

然后,您可以创建三个操作(这可能会在三个线程运行)并等待结果,如下所示:

- (void) operationTestWait 
{ 
    size = 0; 

    self.lock = [[NSLock alloc] init]; 

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 

    NSOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op1"]; 
    NSOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op2"]; 
    NSOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op3"]; 

    [queue addOperations:@[op1, op2, op3] waitUntilFinished:YES]; 

    // do here whatever should happen when the operations are done 
} 

在这种情况下,主线程将等待这三个操作完成。或者更好的是,如果这些任务需要超过几个毫秒,则不应该有主队列等待(因为您应该从不阻塞主队列),而是应该简单地定义您想要的当三个操作完成时主队列要做:

- (void) operationTest 
{ 
    size = 0; 

    self.lock = [[NSLock alloc] init]; 

    NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 

    NSOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op1"]; 
    NSOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op2"]; 
    NSOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(operationMethod:) object:@"Op3"]; 

    NSOperation *completion = [NSBlockOperation blockOperationWithBlock:^{ 

     // if you want this to do something on the main queue, then have this add it to the main queue 

     [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
      // do here whatever should happen when the operations are done 
     }]; 
    }]; 

    // define this completion operation to be dependent upon the above three operations 

    [completion addDependency:op1]; 
    [completion addDependency:op2]; 
    [completion addDependency:op3]; 

    // now add all of them, but don't wait until finished; 
    // but the completion operation will only start when its dependencies 
    // are resolved 

    [queue addOperations:@[op1, op2, op3, completion] waitUntilFinished:NO]; 
} 

原谅啰嗦的答案。如果你能给我们一个更实际的例子,说明这些各种线索将会做什么,我们可以就如何最好地解决它提供更好的建议。但是,一般来说,操作队列或调度队列可能会更有效地解决大多数并发相关的挑战。