2

我想使用以下任务完成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

4

1 回答 1

3

几个想法:

  1. 您说“当 size=10 时将控制权返回给主线程”。这不太合理。主线程永远不会“失去”控制权(因为这些线程是同时发生的)。当这种情况出现时,也许您希望在主线程上发生一些事情?

  2. 您没有让该workerThread方法执行任何循环,因此在您编写它时,每个线程都会执行一次然后退出。您可能需要在此处添加某种形式的循环。

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

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

  5. 一般来说,如果您使用线程(但如果使用队列则没有必要),您应该为您的线程创建一个自动释放池

无论如何,除了这些观察之外,您可能会有以下内容,其中 (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 或操作队列。它们更易于使用,并且具有更好的机制来控制各种任务/操作之间的依赖关系(请参阅并发编程指南)。

例如,考虑与上述方法等效的基于操作的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];
}

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

于 2013-10-10T00:40:39.997 回答