多个NSThreads同步

时间:2013-10-09 23:00:06

标签: ios objective-c multithreading macos nsthread

我想使用NSThread

完成以下任务

我有一个主线程和三(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

并在size=10

时将控件返回主线程

1 个答案:

答案 0 :(得分:3)

有几点想法:

  1. 你说“当size = 10时,将控制权返回给主线程”。这没有多大意义。主线程永远不会“失去”控制(因为这些线程同时发生)。也许你想在这种情况出现时在主线程上发生什么?

  2. 你没有让workerThread方法做任何循环,所以当你编写它时,每个线程都会执行一次然后退出。你可能需要在这里添加一些形式的循环。

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

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

  5. 一般情况下,如果您正在使用线程(但如果使用队列则不需要),您的线程应为creating an autorelease pool

  6. 无论如何,除了这些观察之外,你可能会有以下内容,其中(a)有@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];
    }
    

    说完这一切之后,你开始用“将控制返回到主线程”。正如我之前所说,实际上没有必要这样做,因为在你的例子中,你的应用程序的主线程永远不会产生控制

    为了控制在不同线程上发生的任务之间的关系,我可能建议使用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];
    }
    

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