Objective-Cでマルチスレッドデザインパターンを実装してみた ~Single Threaded Execution~

## はじめに
Java言語のマルチスレッドデザインパターンのObjective-C言語版がないかと探してみましたが、見つからなったので自分で作成してみました。

はじめに Single Threaded Execution パターンを実装してみます。

非同期の実装方法は、Appleの公式ドキュメントで GCD(Grand Central Dispatch) の使用を推奨されているのでそれを利用。

## 環境
- MacOS High Sierra 10.13.6
- Xcode 9.4.1

## スレッドセーフではないサンプルプログラム

まずはスレッドセーフではないGateクラスとUserThreadクラスの実装です。

```objectivec:Gate.h
@interface Gate : NSObject

- (void) pass:(NSString*)name address:(NSString*)address;
- (NSString*) toString;

@end
```

```objectivec:Gate.m
@interface Gate () {
    NSInteger _counter;
    NSString *_name;
    NSString *_address;
}

@end

@implementation Gate

- (id) init {
    if(self = [super init]) {
        _counter = 0;
        _name = @"Nobody";
        _address = @"nowhere";
    }
    return self;
}

- (void) pass:(NSString*)name address:(NSString*)address {
    _counter++;
    _name = name;
    _address = address;
    [self check];
}

- (NSString*) toString {
    return [NSString stringWithFormat:@"No. %@ %@, %@", @(_counter), _name, _address];
}

- (void) check {
    if(![[_name substringToIndex:1] isEqualToString:[_address substringToIndex:1]]) {
        NSLog(@"**** BROKEN **** %@", [self toString]);
    }
}

@end
```

```objectivec:UserThread.h
@interface UserThread : NSObject

- (id) initWithGate:(Gate*)gate name:(NSString*)myName address:(NSString*)myAddress;
- (void) start;

@end
```

```objectivec:UserThread.m
@interface UserThread () {
    Gate *_gate;
    NSString *_myName;
    NSString *_myAddress;
}

@end

@implementation UserThread

- (id) initWithGate:(Gate*)gate name:(NSString*)myName address:(NSString*)myAddress {
    if(self = [super init]) {
        _gate = gate;
        _myName = myName;
        _myAddress = myAddress;
    }
    return self;
}

- (void) start {
    dispatch_queue_t queue = dispatch_queue_create("co.jp.SingleThreadedExecution.Queue", NULL);
    dispatch_async(queue, ^{
        [self run];
    });
}

- (void) run {
    NSLog(@"%@ BEGIN",_myName);
    while (true) {
        [_gate pass:_myName address:_myAddress];
    }
}

@end
```

```objectivec:ViewController.m
- (void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    [self init];
}

- (void)init {
    Gate *gate = [[Gate alloc] init];

    [[[UserThread alloc] initWithGate:gate name:@"Alice" address:@"Alaska"] start];
    [[[UserThread alloc] initWithGate:gate name:@"Bobby" address:@"Brazil"] start];
    [[[UserThread alloc] initWithGate:gate name:@"Chris" address:@"Canada"] start];
}

@end
```

## 実行結果

実行してみると、ログにBROKENが出力されます。

```
Alice BEGIN
Bobby BEGIN
Chris BEGIN
**** BROKEN **** No. 4947 Alice, Alaska
**** BROKEN **** No. 5569 Alice, Alaska
**** BROKEN **** No. 6149 Bobby, Brazil
**** BROKEN **** No. 13204 Chris, Canada
```

## スレッドセーフに修正

Gateクラスを @synchronized を使用してスレッドセーフに修正。


```objectivec:Gate.m
- (void) pass:(NSString*)name address:(NSString*)address {
    @synchronized(self) {
        _counter++;
        _name = name;
        _address = address;
        [self check];
    }
}

- (NSString*) toString {
    NSString *ret;
    @synchronized(self) {
        ret = [NSString stringWithFormat:@"No. %@ %@, %@", @(_counter), _name, _address];
    }
    return ret;
}
```

## 実行結果

実行してみると、ログにBROKENが出力されなくなりました。

```
Alice BEGIN
Bobby BEGIN
Chris BEGIN
```

## サンプルソース

https://github.com/shima-0215/SingleThreadedExecution


## その他

今回 @synchronized を使用しましたが、「スレッドプログラミングガイド」にあるとおりNSLockクラスやNSRecursiveLockクラスを使用してみるのもいいと思います。

## 参考元
- [増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編](https://www.amazon.co.jp/%E5%A2%97%E8%A3%9C%E6%94%B9%E8%A8%82%E7%89%88-Java%E8%A8%80%E8%AA%9E%E3%81%A7%E5%AD%A6%E3%81%B6%E3%83%87%E3%82%B6%E3%82%A4%E3%83%B3%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3%E5%85%A5%E9%96%80-%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%E7%B7%A8-%E7%B5%90%E5%9F%8E-%E6%B5%A9/dp/4797331623/ref=pd_lpo_sbs_14_img_2?_encoding=UTF8&psc=1&refRID=MR6AB4WGRAEPS7PA4ZHM)
- [スレッドプログラミングガイド](https://developer.apple.com/jp/documentation/Multithreading.pdf)
- [並列プログラミングガイド](https://developer.apple.com/jp/documentation/ConcurrencyProgrammingGuide.pdf)
- [エキスパートObjective-Cプログラミング](https://www.amazon.co.jp/%E3%82%A8%E3%82%AD%E3%82%B9%E3%83%91%E3%83%BC%E3%83%88Objective-C%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%EF%BC%8DiOS-OS-X%E3%81%AE%E3%83%A1%E3%83%A2%E3%83%AA%E7%AE%A1%E7%90%86%E3%81%A8%E3%83%9E%E3%83%AB%E3%83%81%E3%82%B9%E3%83%AC%E3%83%83%E3%83%89%EF%BC%8D-%E5%9D%82%E6%9C%AC/dp/4844331094)