2010-10-28 48 views
8

在目标C中有一种方法可以定义一个线程安全的静态int吗?线程安全的静态变量目标c

例如,如果我有一个称为会话类,它具有:

static unsigned int session_id = 1000; 

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

我构建在不同的线程会话对象,每个会话对象 应该有一个唯一的ID。

+0

您需要使用某种锁定语义。问题是你想要操作是原子的。但请记住,“++”不是原子的,它只是一些操作。 – BobbyShaftoe 2010-10-28 02:25:12

+0

是可能的,然后用synchronized(self){return session_id ++}包围我的return session_id ++。但是我不确定这是否会锁定类或它自己的对象。 – Unis 2010-10-28 02:32:09

+0

按照写法,它会锁定实例,而不是类(不是你想要的)。也许“'@synchronized([self class])'”? – 2010-10-28 02:45:33

回答

4

如果你谈论的可可,还有由NSLockNSRecursiveLock提供的互斥功能。

为了正确保护非原子资源,您需要这些互斥锁,以免多个线程可能试图同时更改数据(导致损坏)或使用处于半改变状态的数据(导致无效数据)。如果你不使用可可(或使依稀记得,这是近没用什么小Cocoa编程我与iMac的插曲我记得)

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; 
} 

您的代码将是这个样子,只是使用的概念,将其转换成您有任何语言或框架:

  • 使用或更改受保护的资源之前锁定互斥。
  • 使用或更改资源。
  • 解锁互斥锁。
  • 奖励建议1:尽可能晚地锁定互斥锁并尽快解锁。
  • 奖励建议2:只锁定你需要的东西,这样可以避免不必要的延误。

解释说,最后一点多一些:如果你有两个完全无关的事情上self同步(比如会话ID和用户ID),他们将阻止对方尽管它没有必要这么做。我宁愿使用两个独立的互斥锁来保持较低的粒度。

当然,如果你只有一个会话ID单独的互斥体(但请参阅下面的警告),请随时使用synchronized(self),但我宁愿按照我的方式做,所以我不会被抓到添加其他受保护资源。

在任何情况下(这都是提到的警告),您可能会发现在self上同步将无法充分保护静态变量,该变量将在多个对象之间共享。该互斥量应该属于数据而不是使用它的任何内容。

+0

我来自Java世界,您可以在其中完成:static synchronized int generateID(){return sessionId ++}。这是兼容的,如果我做 - (int)generateSessionID {synchronized(self){return session_id ++;}}? – Unis 2010-10-28 02:42:12

+0

我认为这样做可行,虽然对自己(对象)的锁定可能比我想要的更宽泛。相反,我更喜欢一个特定的互斥量,以避免不必要的互斥量延迟(请参阅我的额外奖励建议)。 – paxdiablo 2010-10-28 02:45:53

+0

@ user489579关闭,但不希望为访问静态变量的实例方法在'self'上同步;可能会在'[self class]'上同步,或者与您正在修改的值直接关联的对象上(例如,将int包装在NSNumber中并在NSNumber上同步)。 – 2010-10-28 02:47:27

8

我认为你最好使用atomic operations修改session_id。 A previous question讨论关于OS X的原子增量/减量操作,this page讨论关于OSAtomic头文件。整数上的原子操作(这些操作很容易被硬件支持)可能比使用锁定构造要快得多。

+1

同意。如果你所做的只是为了得到一个全局递增值而保持静态,那么使用'OSAtomicIncrement32',这将是安全的,并且不具有Cocoa或POSIX同步原语的所有开销。 – 2010-11-20 16:00:56

+1

http://developer.apple。com/library/mac /#文档/可可/概念/多线程/ ThreadSafety/ThreadSafety.html#// apple_ref/doc/uid/10000057i-CH8-SW14 – mcfedr 2012-03-23 13:37:53

1

有很多选项,包括(从高级到低级)@synchronized Objective-C指令,NSLockpthread_mutex_lock和原子操作。

有关详细信息,请阅读Threading Programming Guide的“同步​​”部分。

2

4年后的回应目前在iOS8。 :O) 对我最好的方法是使用一个单独的类,如下所示:

(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 

你只需要为每个新的Id值调用方法'generateSessionId'。 使用这个类来生成你的会话Ids应该足够我想。

希望它能帮助这篇文章的读者。 :o)

+0

@ondermerol:的确如此,它就是这样做的=>'您只需要为每个新的Id值调用方法'generateSessionId'。 – 2015-06-15 08:12:50

+0

对不起,迟到的答案,它的作品像一个魅力,我只犯了一个错误。 – ondermerol 2015-06-22 14:02:24

+1

@ XLE_22:这个线程安全吗?假设thread1调用generateSessionID,那么在thread1有机会检索值之前,thread2调用generateSessionID?他们都不会使用相同的ID吗?如果他们都同时调用这个方法,那么由于没有使用同步工具,是不是有可能导致内存损坏? – jk7 2016-01-08 19:07:09