Потокобезопасные статические переменные цель c - PullRequest
9 голосов
/ 28 октября 2010

Есть ли способ в цели C, чтобы я мог определить статический int, который является потокобезопасным?

например, если у меня есть класс с именем Session, который имеет:

static unsigned int session_id = 1000;

- (int) generateSessionID{
        return session_id++;
}

Я создаю объекты сеанса из разных потоков, каждый объект сеанса должен иметь уникальный идентификатор.

Ответы [ 4 ]

9 голосов
/ 28 октября 2010

Я думаю, вам лучше использовать атомарные операции для изменения session_id. предыдущий вопрос говорит об атомных операциях увеличения / уменьшения для OS X, а эта страница говорит о заголовочном файле OSAtomic.Атомарные операции над целыми числами, которые легко поддерживаются аппаратным обеспечением, вероятно, будут значительно быстрее, чем использование конструкций блокировки.

5 голосов
/ 28 октября 2010

Если вы говорите о Какао, функциональность мьютекса там предоставляется NSLock и NSRecursiveLock.

Чтобы должным образом защитить неатомарный ресурс, вам нужны эти мьютексы, чтобы несколько потоков не моглипопробуйте изменить данные одновременно (что приведет к повреждению) или использовать данные в наполовину измененном состоянии (что приведет к неверным данным).

Ваш код будет выглядеть примерно так:

static NSLock session_id_lock;
static unsigned int session_id = 1000;

- (int) generateSessionID{
    int new_id;
    [myLock lock];
    new_id = session_id++;
    [myLock unlock];
    return new_id;
}

Если вы не используете Какао (или то небольшое программирование Какао, которое я помню из своего короткого интерлюдия с iMac, так смутно запомнилось, что оно почти бесполезно), просто используйте концепцию, переведя ее на любой язык или фреймворк:

  • заблокировать мьютекс перед использованием или изменением защищенного ресурса.
  • использовать или изменить ресурс.
  • разблокировать мьютекс.
  • бонуссовет 1: заблокируйте мьютекс как можно позже и разблокируйте его как можно скорее.
  • бонус совет 2: блокируйте только то, что вам нужно, чтобы избежать ненужных задержек.

Объясняя последний пункт еще немного: если вы синхронизируете self для двух совершенно не связанных между собой вещей (скажем, идентификатора сеанса и идентификатора пользователя), они будут блокировать друг друга, несмотря на то, что в этом нет необходимости.Я бы предпочел два отдельных мьютекса, чтобы сохранить степень детализации на низком уровне.

Конечно, если у вас есть только мьютекс только для идентификатора сеанса (но смотрите предостережение ниже), не стесняйтесь использовать synchronized(self), но я 'Я бы предпочел сделать это по-своему, чтобы потом не попасться при добавлении другого защищенного ресурса.

В любом случае (это упомянутое предостережение) вы, вероятно, обнаружите, что синхронизация на self не будетадекватно защищать статическую переменную, которая будет совместно использоваться несколькими объектами.Мьютекс должен принадлежать данным , а не тому, кто его использует.

2 голосов
/ 01 октября 2014

Ответ через 4 года в настоящее время в iOS8. : О) Лучше всего использовать одноэлементный класс следующим образом:

(yourFile.h)

#import <Foundation/Foundation.h>

@interface singletonSessionId : NSObject

+ (singletonMsgNbr*)sharedSingleton;

- (void)generateSessionId;

@property NSInteger value;

@end

=============================================== ====== (YourFile.m)

#import "singletonSessionId.h"

@implementation singletonSessionId
@synthesize value = _value;

+ (singletonMsgNbr*)sharedSingleton {

    static singletonSessionId *instance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[singletonSessionId alloc]init];
        instance.value = 1000;
    });

    return instance;
}

- (void)generateSessionId {
    _value += 1;
}

@end

Вам просто нужно вызывать метод generateSessionId для каждого нового значения Id. Я думаю, что использование этого класса для генерации ваших сессионных идентификаторов должно быть достаточно далеко.

Надеюсь, это поможет читателям этого поста. : О)

EDIT

Как утверждают некоторые читатели, «значение» NSInteger не является потокобезопасным, поэтому используется только синглтон.

Чтобы получить полную переменную экземпляра 'value' для безопасного потока, просто измените ее тип NSInteger на NSNumber (для преобразования в 'int' соответствующими методами) , то есть полностью безопасен для потоков согласно документации Apple.

Это может быть самый простой и быстрый способ получить желаемое.

1 голос
/ 28 октября 2010

Существует много опций, включая (от высокого уровня до низкого уровня) директиву @synchronized Objective-C, NSLock, pthread_mutex_lock и атомарные операции.

Прочтите «Синхронизация»раздел Руководство по программированию потоков для подробностей.

...