2010-10-28 77 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