Multithreaded programming (ii) use of Nsthread

Source: Internet
Author: User
Tags benchmark posix

iOS 支持多个层次的多线程编程,层次越高的抽象程度越高,使用也越方便。实现多线程的方式有很多,我们主要学习其中的三种实现方式:NSThread,NSOpreationQueue,GCD,这三种编程方式从上到下,抽象度层次是从低到高的,抽象度越高的使用越简单,GCD是抽象程度最高的一种,也是 Apple 最推荐使用的方法。   虽然实现的方式不同,但是操作的对象都是线程,都是对线程的管理。所以,从根本上讲,三者并没有什么不同,可以混合使用,但是并不推荐,因为可能会造成不必要的麻烦。三种多线程的实现方式各有利弊,我们在学习完三种实现方式之后会对它们做出比较。

In this article, we mainly introduce the use of nsthread. The following knowledge points need to be mastered

    • Create a new thread inside a process
    • Modify the properties of a thread
    • Control another thread inside the process
    • Synchronous data access between threads within a process
    • To view the state in which a thread is running
1. Thread Overhead

Before we learn how to implement multithreading, let's look at a very important concept, threading overhead. The thread overhead of creating a new thread is significantly smaller than creating a new process (although Linux is particularly efficient in creating new processes), which is an important reason for our multithreaded development.

Thread overhead: Threads are required for memory and performance overhead, and memory overhead includes system kernel memory and application memory: The kernel structure used to manage and reconcile threads is stored in the kernel, the thread's stack space, and each thread's data is stored in the program's memory space, Most of these structures that occupy memory are generated and initialized at the time of thread creation. Because threads interact with the kernel, this process is very time consuming, which is the main reason for the performance overhead of threads. The approximate cost of thread creation is as follows (where the stack space for the second thread is configurable):

    • Kernel data structure: approximately 1KB
    • Stack space: The main thread is about 1MB, and the second is about 512KB
    • Thread creation time: approximately 90 milliseconds
    • Another overhead is the overhead of program thread synchronization.
2. Introduction to Nsthread

Nsthread is the upper-level encapsulation of pthread, which handles threading as object-oriented logic. A nsthread represents a thread.

The advantage of Nsthread is that Nsthread is a lightweight approach to multithreading. But Nsthread's shortcomings are equally obvious, requiring itself to manage thread lifecycles and thread synchronization. At the same time, using Nsthread to implement thread synchronization to lock the data will have a certain system overhead.
Nsthread implements the following three types of technologies:

Technology Description
Cocoa Threads Cocoa implements threads using the Nsthread class. Cocoa also provides methods on NSObject for spawning new threads and executing code on already-running threads. For the information, see "Using Nsthread" and "using NSObject to Spawn a Thread." Cocoa implements threading using the Nsthread class. Cocoa also provides methods to execute code on NSObject generation of new threads and running threads. For more information, see "Using Nsthread" and "building a thread with NSObject".
POSIX threads POSIX threads provide a c-based interface for creating threads. If you aren't writing a COCOA application, this is the best choicefor creating threads. The POSIX interface is relatively simple-to-use and offers-ample flexibility for configuring your threads. For more information, the See "Using POSIX Threads" POSIX thread provides a C-based interface to create threads. If you do not write cocoa applications, this is the best choice to create threads. POSIX interfaces are relatively simple to use and configuration threads provide ample flexibility. For more information, see "Using POSIX threads"
Multiprocessing Services Multiprocessing Services is a legacy c-based interface used by applications transitioning from older versions of Mac OS. This technology are available in OS X and should are avoided for any new development. Instead, you should use the Nsthread class or POSIX threads. If you need much information on this technology, see multiprocessing Services Programming Guide. The multi-processing service is a legacy C-based interface used by the application, from Older versions of Mac OS transitions. This technology can be in OS X only and should avoid any new developments. Instead, you should use the Nsthread class or POSIX thread. In this technique, if you need more information, see the Multi-processing service Programming Guide.

We generally recommend the use of cocoa thread technology.

    • Cocoa Threads: Use Nsthread or directly from the NSObject class method Performselectorinbackground:withobject: To create a thread. If you choose thread to implement multi-threading, then nsthread is the preferred way to use the official recommendation.
    • POSIX Threads: (Portable Operating system interface) a multi-line libraries based on C language is a cross-platform multi-threaded implementation method. Pthread is a common line libraries, which is widely supported by various UNIX and is proposed by POSIX. Therefore, it has very good portability. Many OSes are compatible with POSIX thread, such as linux/windows, and even embedded systems (such as rt-thread) support the POSIX thread API.
3. Creation and operation of the Nsthread using 3.1 nsthread

Nsthread is initialized in a total of 4 ways:

    • show how to create

      Parameter meaning:
      Selector: The method that the thread executes, this selector can only have one parameter, and cannot have the return value. We know that each thread has a main method, and selector is the entry method for that thread, which is equivalent to the thread's main function, which is equivalent to the method in which the self in the main function calls the selector.
      Target:selector the object sent by the message,
      Argument: The only parameter transmitted to target, or nil
      code example:

    • Implicit creation Method

      Parameter meaning:
      Selector: The method that the thread executes, this selector can only have one parameter, and cannot have the return value.
      Target:selector object sent by message
      Argument: The only parameter transmitted to target, or nil
      code example

      上面两种方法是NSTread类提供的直接创建线程的方式。第一种方式会先创建线程对象,然后再调用start方法运行线程操作;第二种方式是直接创建线程并且开始运行线程。同时第一种创建方式可以得到一个线程对象,在运行线程操作前可以设置线程的优先级等线程信息,这点我们会在下面做具体的讲解。
    • Thread extension methods using NSObject:
      A class (Nsthreadperformadditions) was created in Nsthread, which extends the implementation of multithreading for NSObject, using the same method as the previous one.

      code example:

    • Create a Nsthread subclass

      Create a subclass based on the Nsthread class, and then instantiate and invoke the Start method to run the threading operation, note that in initializing the subclass is, you need to make a copy of the main function as the thread's entry.


      It should be emphasized that, after the main function is overwritten, the entry for the thread has already been made, and the entry function of the thread does not need to be specified. So the following usage is meaningless, because when we make a copy of the main function, the thread's entry changes, making the Selecter parameter meaningless.

3.2 Configuring Thread Parameters
  • StackSize: Configure line Stacks space

    The stack space is used to store local variables created for threads, and the size of the stack space must be set before the thread is created, that is, before calling Nsthread's Start method via Setstacksize: Sets the new stack space size.

  • Threaddictionary: Configuring local storage for Threads

    Each thread maintains a dictionary that can be obtained from anywhere on the line. We can use Nsthread's Threaddictionary method to get a Nsmutabledictionary object, and then add the fields and data we need.

  • ThreadPriority: Setting the priority of a thread

    Thread priority can be set through Nsthread's setthreadpriority: Method, a double type with a priority of 0.0 to 1.0, and 1.0 as the highest priority. Replaced by QualityOfService in IOS 8 update. Each new thread has a default priority. The kernel scheduling algorithm of the system determines the order in which threads are executed based on the priority of the thread. In general, we do not change the priority of the thread, increasing the priority of some threads may cause the low priority thread to continue to be executed, if there are high-priority threads and low-priority threads in our application interaction, because the low-priority threads do not get execution may block the execution of other threads. This can create a performance bottleneck for your application.

  • Set the detached, joinable state of a thread

  • Out-of-thread (Detach thread)-When the thread finishes, the system automatically frees the memory space it occupies

  • Joinable thread-threads are not recycled after the thread has finished the resources that can be connected

    When an application exits, the disengagement thread can be interrupted immediately, while the thread that can connect is not. Each connected thread must be connected when the process is allowed to exit. So when a thread is working periodically and not allowed to be interrupted, such as saving data to a hard disk, a thread that can be connected is the best choice.
    Of course, in iOS development, we rarely need to create a thread that can be connected. Threads created through Nsthread are out-of-thread. If you want to create a threaded connection, the only way to do this is to use a POSIX thread. POSIX threads created by default are available for connection. Sets whether the property is detached by the pthread_attr_setdetachstate function.

Common methods of 3.3 nsthread
  NSThread类给我们提供了一下几个常用方法

3.4 Communication between threads
    在一个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信。例如,执行下载网络图片的任务时,为了避免由于网络延迟造成主线程的卡死,我们开辟一条线程执行下载任务,但是由于操作UI的任务必须在主线程中进行,所以图片下载完成后需要回到主线程完成加载图片的任务。   线程间通信的主要表现在:一个线程传递数据给另一个线程,或者是在一个线程中执行完特定任务后,转到另一个线程继续执行任务。线程间通信常用方法:

Parameter explanation:

    • @selector define the method we want to execute.
    • Withobject:arg defines the parameter object that is passed in when we execute the method, and the type is the ID.
    • WAITUNTILDONE:YES Specifies whether the current thread will be blocked until the main thread finishes executing the block of code we have made.
    • Modes:array Specifies the mode at which time runs.

      (1) The function of the first two methods is to execute the specified method in the main thread. This method is primarily used to callback to the main thread to modify the state of the page UI. Waituntildone: The setting parameter is Yes is not valid when the current thread is the main path.
      (2) The function of the latter two methods is to execute the specified method in the specified thread. Note that the thread that specifies the task must have runloop.

3.5 Example Exercises
我们通过一个示例来联系一下NSThead的使用,当我们在加载网络图片时,由于网络延迟,图片可能很长时间才能完成加载,这时候,为了避免造成主线程的卡死,我们可以把下载网络图片的任务交给一个新的线程,当图片完成下载之后再回到主线程完成图像的加载显示。   代码如下:
    • Create a class for the Uiimageview class, add a method: Setimagewithurl: (nsstring*) urlstring; open a sub-thread, complete the task of downloading pictures;
    • Download the network picture in the sub-thread, the download succeeds and return to the main thread, complete the loading task of the picture, because the system requires all the tasks that the UI wants to complete in the main thread.
    • After the picture is downloaded, the image is loaded and the method needs to be completed in the main thread.
4. Thread-Perfect Entry 4.1 autorelease Pool
   如果新开辟的线程没有Autorelease Pool的话,那么在新线程中生成的Autorelease对象会存放到主线程的Autorelease Pool中,当新开辟的线程被终止时,线程中的Autorelease对象不会被最终释放掉,占用主线程资源。所以我们需要在线程的入口处我们需要创建一个Autorelease Pool,当线程退出的时候释放这个Autorelease Pool。这样在线程中创建的autorelease对象就可以在线程结束的时候释放,避免过多的延迟释放造成程序占用过多的内存。如果是一个长寿命的线程的话,应该创建更多的Autorelease Pool来达到这个目的。例如线程中用到了Runloop的时候,每一次的迭代都需要创建 Autorelease Pool。
4.2 Setting up the Run Loop
   当创建线程的时候我们有两种选择,一种是线程执行一个很长的任务然后再任务结束的时候退出。另外一种是线程可以进入一个循环,然后处理动态到达的任务,这时候就需要我们开启线程的RunLoop了。每一个线程默认都有一个 NSRunloop,主线程是默认开启的,其他线程要手动开启。
4.3 Terminating a thread
   终止线程最好不要用POSIX接口直接杀死线程,这种粗暴的方法会导致系统无法回收线程使用的资源,造成内存泄露,还有可能对程序的运行造成影响。终止线程最好的方式是能够让线程接收取消和退出消息,这样线程在受到消息的时候就有机会清理已持有的资源,避免内存泄露。如果需要在子线程运行的时候让子线程结束操作,子线程每次Run Loop迭代中检查相应的标志位来判断是否还需要继续执行,可以使用threadDictionary以及设置Input Source的方式来通知这个子线程。这种方案的一种实现方式是使用NSRunloop的input source来接收消息,每一次的 NSRunloop循环都检查退出条件是否为YES,如果为YES退出循环回收资源,如果为NO,则进入下一次NSRunloop循环。
5. Thread Synchronization
有时候需要我们设置线程同步,但是线程同步往往会产生很多问题:1. 线程的死锁。即较长时间的等待或资源竞争以及死锁等多线程症状。2. 对公有变量的同时读或写。当多个线程需要对公有变量进行写操作时,后一个线程往往会修改掉前一个线程存放的数据,从而使前一个线程的参数被修改;另外 ,当公用变量的读写操作是非原子性时,在不同的机器上,中断时间的不确定性,会导致数据在一个线程内的操作产生错误,从而产生莫名其妙的错误,而这种错误是程序员无法预知的。
5.1 Data Sync Lock
   在多个线程访问相同的数据时,有可能会造成数据的冲突。比如常见的售票问题。
    • It is the most common way to resolve this issue by using lock-in mode. The Nslock object is provided in the Foundation framework to implement the lock.

      [Lock lock];//Plus lock
      [Lock unlock];//unlock

    • This problem can also be resolved by setting the atomicity of the property

      Atomic: The default is the property, this property is to ensure that the program in the multi-threaded case, the compiler will automatically generate some mutex lock code, to avoid the variable read and write synchronization problems.

      Nonatomic: If the object does not need to consider multithreading, add this property, which will allow the compiler to generate a few mutually exclusive lock code, can improve efficiency.

      Atomic means setter/getter This function, which is an atomic operation. If more than one thread calls the setter at the same time, the other thread starts executing the setter condition before one thread finishes executing all the setter statements. Equivalent to the function of the tail and the same lock, can guarantee the integrity of the data. Nonatomic does not guarantee the setter/getter of the original line, so you may be able to take something incomplete. Therefore, in multi-threaded environment atomic operation is very necessary, otherwise it may cause incorrect results. For example, the setter function changes two member variables, if you use Nonatomic, getter may be taken to change only one of the variables when the state, so that the things can be a problem, is incomplete. Of course, if you do not need multi-threading support, with Nonatomic is enough, because it does not involve the operation of the lock, so it is relatively faster execution rate.

      In a generic iOS program, all properties are declared as nonatomic. The reason for this is that the cost of using a sync lock in iOS is large, which can cause performance problems. In general, it is not required that the attribute must be "atomic" because it does not guarantee "thread safety", and to achieve "thread-safe" operation, a deeper locking mechanism is needed to wake up. For example, when a thread reads a property value several times in a row, and another thread overwrites the value at the same time, it will read a different property value even if the property is declared as atomic. As a result, iOS programs generally use the Nonatomic property. However, there is usually no performance bottleneck when using the Atomic property in Mac OS x programs

5.2 Synchronous Wait
多线程中经常遇到一种问题,A线程需要等待B线程执行后的某个结果继续执行,也就是同步问题,这时就会需要A等待B,这里说说使用NSCondition实现多线程同步的问题,也就是解决生产者消费者问题(如收发同步等等)。

The problem flow is as follows:

    • The consumer obtains the lock, takes the product, if does not have, then wait, then will release the lock, until the thread wakes it to consume the product;
    • The producer manufactures the product, first also must obtain the lock, then produces, then sends the signal, this can awaken wait the consumer.

      Here are some things to watch for wait and signal:

      1. In fact, the wait function silently calls the unlock function (guess, interested in self-analysis), that is, after calling the Wati function, the Nscondition object is in a lock-free State, This allows other threads to lock the object and trigger the Nscondition object. When Nscondition is triggered by another thread, the notification is triggered inside the wait function, and then the lock function (guess) is recalled for this event. and externally it looks as if the thread that receives the event (the thread that calls wait) never releases ownership of the Nscondition object, and the Wati thread enters the trigger state directly from the blocking state. It is easy to cause misunderstanding here.
      2. The wait function is not completely trustworthy. That is, when wait returns, does not mean that the corresponding event must be triggered, so in order to ensure synchronization between threads, the use of nscondtion often need to add an additional variable to avoid the abnormal wait return.
      3. With regard to the order of calls for multiple wait, test discovery is related to the wait execution order.
6. Status of the thread

Thread creation and opening:

self.thread = [[NSThread alloc]initWithTarget:self selector:@selector(test) object:nil]; [self.thread start];

Running and blocking of threads:

   // 设置线程阻塞1,阻塞2秒   [NSThread sleepForTimeInterval:2.0];   // 第二种设置线程阻塞2,以当前时间为基准阻塞4秒   NSDate *date=[NSDate dateWithTimeIntervalSinceNow:4.0];   [NSThread sleepUntilDate:date];

Performance in memory when a thread handles a blocking state: (Threads are moved out of the scheduler thread pool, not scheduled at this time)

Thread of death:
When a thread's task ends, an exception occurs, or a forced exit of these three cases causes the thread to die.

After the thread dies, the thread object is removed from memory.

code Example 1:

- (void) Viewdidload {[SuperViewdidload];//Create thread      Self. Thread=[[NsthreadAlloc]initwithtarget: SelfSelector@selector(Test) object:Nil];//Set the name of the thread[ Self. Threadsetname:@"Thread A"]; }//When the finger is pressed, turn on the thread-(void) Touchesbegan: (Nsset *) touches withevent: (Uievent *) Event {//Open thread[ Self. ThreadStart]; } -(void) Test {//Get thread     Nsthread*current=[NsthreadCurrentThread];NSLog(@"Test---print thread---%@", Self. Thread. Name);NSLog(@"Test---thread started---%@", current. Name);//Set thread to block 1, block for 2 seconds     NSLog(@"Next, the thread blocks for 2 seconds"); [NsthreadSleepfortimeinterval:2.0];///second set thread Block 2, 4 seconds for current time benchmark      NSLog(@"Next, the thread blocks for 4 seconds");NSDate*date=[NSDateDatewithtimeintervalsincenow:4.0]; [NsthreadSleepuntildate:date]; for(intI=0; i< -; i++) {NSLog(@"Thread--%d--%@", i,current. Name); }NSLog(@"Test---thread end---%@", current. Name); }

Print View:

code example 2 (Exit thread):

- (void) Viewdidload {[SuperViewdidload];//Create thread      Self. Thread=[[NsthreadAlloc]initwithtarget: SelfSelector@selector(Test) object:Nil];//Set the name of the thread[ Self. Threadsetname:@"Thread A"];}//When the finger is pressed, turn on the thread-(void) Touchesbegan: (Nsset *) touches withevent: (Uievent *) Event {//Open thread[ Self. ThreadStart]; } -(void) Test {//Get thread     Nsthread*current=[NsthreadCurrentThread];NSLog(@"Test---print thread---%@", Self. Thread. Name);NSLog(@"Test---thread started---%@", current. Name);//Set thread to block 1, block for 2 seconds     NSLog(@"Next, the thread blocks for 2 seconds"); [NsthreadSleepfortimeinterval:2.0];///second set thread Block 2, 4 seconds for current time benchmark      NSLog(@"Next, the thread blocks for 4 seconds");NSDate*date=[NSDateDatewithtimeintervalsincenow:4.0]; [NsthreadSleepuntildate:date]; for(intI=0; i< -; i++) {NSLog(@"Thread--%d--%@", i,current. Name);if(5==i) {//End thread[NsthreadExit]; }     }NSLog(@"Test---thread end---%@", current. Name); }

Print Example:

Note: If you click on the screen again to try to turn the thread back on, the program hangs.

Summary:
NSThread 作为多线程编程的重要的工具类,我们应该尝试使用并理解其中的方式。但是NSThread的缺点很明显,我们需要手动实现非常复杂的管理线程逻辑,自己管理线程的生命周期,线程同步。线程同步对数据的加锁会有一定的系统开销。当然他的优点同样明显比其他两种多线程方案较轻量级,更直观地控制线程对象。

Multithreaded programming (ii) use of Nsthread

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.