Sharing is an essential quality for every good programmer


An NSThread object represents a thread, a lightweight thread operation whose lifecycle is controlled by the programmer and released when the task is completed.

Create and start a thread

There are three ways to create code:

  • 1. alloc initTo create a thread, start the thread manually
- (void)createNewThread1{ //1. Create thread // third argument object: NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@ (run:) object:@"rc"]; Thread. name = @" thread RC"; Thread.threadpriority = 1.0; thread.threadPriority = 1.0; thread.threadPriority = 1.0; /* New thread priority @property NSQualityOfService qualityOfService; NSQualityOfServiceUserInteractive --> Main thread NSQualityOfServiceUserInitiated --> HIGH NSQualityOfServiceUtility -->  LOW NSQualityOfServiceBackground --> Background NSQualityOfServiceDefault --> Default */ // thread.qualityOfService = NSQualityOfServiceDefault; //2. Start thread [thread start]; }Copy the code
  • 2, separate the child thread, automatically start the thread
-(void)createNewThread2{[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject: @selector]; }Copy the code
  • 3. Start a background thread and start automatically
- (void) createNewThread3 {[self performSelectorInBackground: @ the selector (run) withObject: @ "open background threads"]; } -(void)run:(NSString *)param{ NSLog(@"---run----%@---%@",[NSThread currentThread],param); }Copy the code

Print:

RCNSThreadDemo[4644:223899] ---run----<NSThread: 0x600000A98480 >{number = 3, name = thread RC}-- RC RCNSThreadDemo[4644:223901] --run----<NSThread: 0x600000A98A00 >{number = 4, name = (null)}-- Separate child thread RCNSThreadDemo[4644:223902] --run----<NSThread: 0x600000A99740 >{Number = 5, Name = (NULL)}-- Start background threadCopy the code
  • Main thread related usage
+ (NSThread *)mainThread; // Get the main thread - (BOOL)isMainThread; + (BOOL)isMainThread; // Whether the thread is the main threadCopy the code
  • Get the current thread
NSThread *current = [NSThread currentThread];
Copy the code

Thread state

Threads have five states: New, ready, running, blocked, and dead

  • Start thread: Enter ready state -> Run state. The thread enters the dead state automatically when the task is completed
 - (void)start; 
Copy the code
  • Block (pause) a thread: Enters a blocked state
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
Copy the code
  • Force a thread to stop: Enter the dead state
 + (void)exit;
Copy the code

Note: Once a thread has stopped (died), the task cannot be started again

Thread safety

The same resource may be shared by multiple threads, that is, multiple threads may access the same resource. For example, multiple threads access the same object, variable, and file. When multiple threads access the same resource, data corruption and data security problems may occur

Analysis chart of security risks provided by Apple:

Thread A and thread B simultaneously read the same address to get 17. Thread A adds 1 to get 18 and then writes. Thread B adds 1 to get 18 and then writes. Apparently, 17 did +1 twice and got 18!! Security concerns arise when multiple threads access the same object with unexpected results. Apple has a solution:

As shown above, when ThreadA adds a lock before accessing a resource, it performs the lock operation. Read the resource, perform the + 1 operation, write the resource, unlock the resource, and perform the UNLOCK operation. During this time, the resource cannot be accessed by any other Thread until the UNLOCK operation is complete. The other threads are in the wait state. Note: locking costs resources.

Check out this article on iOS thread locks and their performance

To paraphrase:

Atomic and non-atomic properties

OC has both nonatomic and atomic options for defining attributes, and presumably most of us use nonatomic

  • Atomic: Atomic property, which is essentially locking setter methods (atomic by default). As mentioned above, the thread after locking is safe, but consumes a lot of resources.
  • Nonatomic: Non-atomic property, does not lock setter methods, is not thread-safe, suitable for mobile devices with small memory

The recommendation is that all attributes be declared nonatomic; Try to avoid multi-thread snatching the same resource; Try to transfer the service logic of locking and resource snatching to the server to reduce the pressure on mobile clients.

Create 3 threads from 0 to +1 until greater than 10 to stop the code:

@property (nonatomic,assign) NSInteger totalCount; - (void)createSafeThread{ self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(getTotal) object:nil]; [self.threadA start]; [self.threadB start]; [self.threadC start]; } - (void)getTotal{ while (1) { NSInteger count = self.totalCount; If (count < 10) {for (NSInteger I = 0; i<88888; i++) { NSInteger a = 1; NSInteger b = 1; a = a + b; } self.totalCount = count + 1; NSLog(@"--*-**----%ld",self.totalCount); }else{ break; }}}Copy the code

We would expect to print from 1 to 10, but let’s look at the actual print:

RCNSThreadDemo[1763:182366] ------1 RCNSThreadDemo[1763:182365] ------2 RCNSThreadDemo[1763:182364] ------2 RCNSThreadDemo[1763:182365] ------3 RCNSThreadDemo[1763:182364] ------4 RCNSThreadDemo[1763:182366] ------3 RCNSThreadDemo[1763:182365] ------5 RCNSThreadDemo[1763:182364] ------5 RCNSThreadDemo[1763:182366] ------6 RCNSThreadDemo[1763:182364] ------7Copy the code

It’s easy to see there’s a problem, but it’s even more obvious if you simulate it using GCD. Adding asynchronous tasks to a for loop in a concurrent queue looks like replication, causing bad memory access and program crashes.

Adding a mutex will solve the problem. Here we use:

@synchronized

Use the format: @synchronized {// code to lock}, where the lock object must be unique, generally passing self or a global variable of the current, such as self.threada. Note: locking one piece of code takes only one lock. Multiple locks do not work

Pros and cons of mutex

  • Advantages: It can effectively prevent data security problems caused by multi-thread resource grabbing
  • Disadvantages: Consumes a lot of CPU resources

Prerequisite: The mutex will cause thread synchronization, that is, multiple threads execute tasks on the same line (in sequence).

The code:

- (void)getTotal{ while (1) { @synchronized (self) { NSInteger count = self.totalCount; If (count < 10) {for (NSInteger I = 0; i<88888; i++) { NSInteger a = 1; NSInteger b = 1; a = a + b; } self.totalCount = count + 1; NSLog(@"------%ld",self.totalCount); }else{ break; }}}}Copy the code

Interthread communication

Common methods of communication between threads

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

Copy the code

Take downloading images as an example:

- (void)downloadImage{ [NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:nil]; } - (void)download{ NSURL *url = [NSURL URLWithString:@"http://00.minipic.eastday.com/20170227/20170227134901_e45455144ba23b7cee75f292229151b1_21.jpeg"]; NSData *imageData = [NSData dataWithContentsOfURL:url]; UIImage *image = [UIImage imageWithData:imageData]; WaitUntilDone: whether to wait, // [self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES]; / / the second [self imageView performSelectorOnMainThread: @ the selector (setImage:) withObject: image waitUntilDone: YES]; } // update UI operation -(void)showImage:(UIImage *)image{self.imageview.image = image; NSLog(@"UI----%@",[NSThread currentThread]); }Copy the code

Very simple, start a child thread to download the image, and then go to the main thread to update the UI.


Personal shallow view, wrong place welcome correction