[iOS development - multi-threading [4] pthread&NSThread

Preface

The last article on multi-threading, from GCD API to GCD implementation, I learned NSOperationand NSOperationQueuegradually understood the usage scenarios and many principles of multi-threading, many of which involve other knowledge, locks, etc.

This blog is about learning the commonly used things in iOS NSThreadand understanding them pthread(not commonly used).

Introduction to pthreads

pthread is a set of general multi-threaded APIs that can be used across platforms such as Unix/Linux/Windows. It is written in C language and requires programmers to manage the life cycle of threads themselves. It is difficult to use. We almost never use it in iOS development. Not using pthreads.

Wikipedia introduction: POSIXThreads (English: POSIX Threads, often abbreviated as Pthreads) is the thread standard POSIXof , which defines a set of APIs for creating and manipulating threads.
The library that implements POSIXthe thread standard is often called a thread standard Pthreadsand is generally used Unix-like POSIXin systems such Linuxas Solaris.

Simply put, this is a thread used at the operating system level. It is implemented based on C language. It is rarely used in our OC code and is not easy to manage.

pthread_mutex

The reason for mentioning him is that pthreadI think the most contacted thing is the mutex lock itself, including the iOS NSLock lock, which is also based on the pthread_mutex encapsulated lock, just briefly mention it.
pthread_mutexIt is the data type used to implement mutex in the POSIX thread library. Mutex lock is a synchronization mechanism used to protect mutually exclusive access to shared resources in a multi-threaded environment and prevent race conditions caused by multiple threads modifying the same resource at the same time.

Here are pthread_mutexsome important operations:

  1. Create a mutex lock: Use pthread_mutex_inita function to initialize a mutex lock object and specify the properties of the lock. For example, you can choose to create a normal lock or a recursive lock.
  2. Locking: Use pthread_mutex_locka function to lock a mutex before accessing a shared resource. If the mutex is already locked by another thread, the current thread will be blocked until the mutex is available.
  3. Attempt to lock: Use pthread_mutex_trylockthe function to try to lock the mutex. The function returns immediately, with success or failure depending on the status of the mutex lock.
  4. Unlock: Use pthread_mutex_unlocka function to release the mutex, making it available for use by other threads. The unlocking operation should occur after accessing the shared resource so that other threads can acquire the mutex lock.
  5. Destroy the mutex lock: Use pthread_mutex_destroythe function to destroy the mutex lock object and release related resources.

Mutex locks provide a thread synchronization mechanism to ensure that only one thread can access protected shared resources at any time, thus avoiding data competition and uncertain behavior. It is one of the synchronization tools commonly used when writing multi-threaded programs.

Use of pthread

  • First introduce the header file#import <pthread.h>
  • We need to create a thread and start the thread to perform tasks.
// 1. 创建线程: 定义一个pthread_t类型变量
pthread_t thread;
// 2. 开启线程: 执行任务
pthread_create(&thread, NULL, run, NULL);
// 3. 设置子线程的状态设置为 detached,该线程运行结束后会自动释放所有资源
pthread_detach(thread);

void * run(void *param)    // 新线程调用方法,里边为需要执行的任务
{
    
    
    NSLog(@"%@", [NSThread currentThread]);

    return NULL;
}

pthread_create(&thread, NULL, run, NULL);The meaning of each parameter in:

  • The first parameter &thread is the thread object, a pointer to the thread identifier
  • The second is the thread attribute, which can be assigned NULL
  • The third run represents the pointer to the function (the corresponding function of run is the task that needs to be executed in the new thread)
  • The fourth is the parameter of the running function, which can be assignedNULL

pthreadAPI

  • pthread_create(pthread_t _Nullable *restrict _Nonnull, const pthread_attr_t *restrict _Nullable, void * _Nullable (* _Nonnull)(void * _Nullable), void *restrict _Nullable);Create a thread
  • pthread_exit(void * _Nullable); Terminate a thread
  • pthread_cancel(pthread_t _Nonnull);Interrupt the running of another thread
  • pthread_join(pthread_t _Nonnull, void * _Nullable * _Nullable); Block the current thread until another thread ends
  • pthread_attr_init(pthread_attr_t * _Nonnull); Initialize thread properties
  • pthread_attr_setdetachstate(pthread_attr_t * _Nonnull, int);Set the properties of the detached state
  • pthread_attr_getdetachstate(const pthread_attr_t * _Nonnull, int * _Nonnull); Set the properties of the detached state
  • pthread_attr_destroy(pthread_attr_t * _Nonnull); Delete thread attributes
  • pthread_kill(pthread_t _Nonnull, int);Send a signal to the thread

Just understand

NSThread

Insert image description here

Although contrast GCDand NSOperationare not commonly used, it is still the multi-threading technology provided by OC and is occasionally used.

NSThreadIt is officially provided by Apple. It is pthreadmore object-oriented in use, simple and easy to use, and can directly operate thread objects. However, programmers also need to manage the life cycle of threads themselves (mainly creation). We occasionally use NSThread during the development process. For example, it is often called [NSThread currentThread]to display the current process information.

Create and start threads

NSThread provides three methods

  • Create a thread and start the thread manually
// NSThread 先创建线程,再启动线程
- (void)JP_NSThread_1 {
    
    
    // 1. 创建线程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    // 2. 启动线程
    [thread start];    // 线程一启动,就会在线程thread中执行self的run方法
}
  • Create threads and automatically start threads
// 创建线程后自动启动线程
- (void)JP_NSThread_2 {
    
    
    // 1. 创建线程
    [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
  • Implicitly create and start threads
// 隐式创建并启动线程
- (void)JP_NSThread_3 {
    
    
    [self performSelectorInBackground:@selector(run) withObject:nil];
}
// 新线程调用方法,里边为需要执行的任务
- (void)run {
    
    
    NSLog(@"%@", [NSThread currentThread]);
}

API provided by NSThread

This code involves NSThreadsome methods and properties of the class, which are used to obtain and operate thread-related information. Here's an explanation of each part:

  1. + (NSThread *)mainThread;
    This is a class method used to obtain NSThreadthe object of the main thread (Main Thread) . The main thread is the main execution thread of the application, on which UI operations and other important tasks are performed.

  2. - (BOOL)isMainThread;
    This is an instance method used to determine whether the current thread is the main thread . Returns if the thread calling this method is the main thread, YESotherwise NO.

  3. + (BOOL)isMainThread;
    This is a class method used to determine whether the current thread is the main thread . Similar to instance methods, but can be called directly through the class name.

  4. NSThread *current = [NSThread currentThread];
    This line of code gets NSThreadthe object of the current thread . You can use this object to access and manipulate the properties and methods of the current thread.

  5. - (void)setName:(NSString *)n;
    This is an instance method used to set the thread's name . You can identify and identify threads by giving them a meaningful name.

  6. - (NSString *)name;
    This is an instance method used to get the name of the thread . Returns the thread's name string.

Thread state control method

  • Start thread

The thread enters the ready state -> running state . When the thread task is executed, it automatically enters the death state.

- (void)start;
  • Block/pause thread
+ (void)sleepUntilDate:(NSDate *)date;

This method causes the current thread to pause execution until the specified date. That is, the thread will sleep until the specified date and time is reached before continuing execution.

+ (void)sleepForTimeInterval:(NSTimeInterval)time;

This method causes the current thread to pause execution for a period of time, in seconds. The thread will sleep for the specified time before continuing execution.

These two methods can be used for thread control, such as when you need to pause the thread for a period of time before proceeding to the next step . ⚠️These methods will block the execution of the current thread, so they need to be used with caution to avoid adversely affecting the response performance of the application.

  • Force stop thread

Thread enters death state

+ (void)exit;

Communication between threads

In development, we often perform time-consuming operations on sub-threads, and then return to the main thread to refresh the UI after the operation is completed. This involves communication between the child thread and the main thread.

  • Perform operations on the main thread
// 在主线程上执行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

This method executes the specified method on the main thread. Parameter aSelectoris the selector (method name) of the method to be executed, and argis the object parameter passed to the method, waitindicating whether to wait for execution to complete before returning. If wait, YESthe current thread will wait for execution to complete before continuing. If NO, it will return immediately.

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;
  // equivalent to the first method with kCFRunLoopCommonModes

This method is similar to the previous method, but it also accepts a modesparameter that specifies the run mode in which the method is executed (Run Loop Modes). modesThe argument is an array of strings specifying the name of the run mode. The running mode of the main thread defines under which circumstances events and methods can be processed.

Calling this method puts the specified method into the task queue of the main thread to ensure execution on the main thread. At the same time, you can specify the running modes in which events can be processed and methods executed through the modes parameter.

This method is very useful in a multi-threaded environment, especially when operations related to interface interaction need to be performed on the main thread. For example, when updating UI elements or executing code blocks that need to be executed on the main thread, you can use this method to switch tasks to the main thread for execution, ensuring the correct thread execution context, and avoiding situations where the interface freezes or becomes unresponsive.

  • Perform operations on specified thread
- (id)performSelector:(SEL)aSelector;

Is NSObjecta method of the class, used to execute the specified method in the current thread and return the return value of the method .

- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
  • Perform operations on the current thread
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);

Demo (reference)

  • Start a sub-thread and download images in the sub-thread.
  • Return to the main thread to refresh the UI and display the image in UIImageView.
/**
 * 创建一个线程下载图片
 */
- (void)downloadImageOnSubThread {
    
    
    // 在创建的子线程中调用downloadImage下载图片
    [NSThread detachNewThreadSelector:@selector(downloadImage) toTarget:self withObject:nil];
}

/**
 * 下载图片,下载完之后回到主线程进行 UI 刷新
 */
- (void)downloadImage {
    
    
    NSLog(@"current thread -- %@", [NSThread currentThread]);
    
    // 1. 获取图片 imageUrl
    NSURL *imageUrl = [NSURL URLWithString:@"https://ysc-demo-1254961422.file.myqcloud.com/YSC-phread-NSThread-demo-icon.jpg"];
    
    // 2. 从 imageUrl 中读取数据(下载图片) -- 耗时操作
    NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
    // 通过二进制 data 创建 image
    UIImage *image = [UIImage imageWithData:imageData];
    
    // 3. 回到主线程进行图片赋值和界面刷新
    [self performSelectorOnMainThread:@selector(refreshOnMainThread:) withObject:image waitUntilDone:YES];
}

/**
 * 回到主线程进行图片赋值和界面刷新
 */
- (void)refreshOnMainThread:(UIImage *)image {
    
    
    NSLog(@"current thread -- %@", [NSThread currentThread]);
    
    // 赋值图片到imageview
    self.imageView.image = image;
}

State transitions between threads

When we create a new thread NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];, its performance in memory is:

Insert image description here

  • When [thread start]; is called, the system puts the thread object into the schedulable thread pool, and the thread object enters the ready state, as shown in the figure below.
    Insert image description here
  • Of course, there will be other thread objects in the schedulable thread pool, as shown in the figure below. Here we only care about the thread object on the left.

Insert image description here
How to understand the thread transition of the current thread

  • If the CPU now schedules the current thread object, the current thread object enters the running state. If the CPU schedules other thread objects, the current thread object returns to the ready state.
  • If the CPU calls the sleep method to wait for the synchronization lock when running the current thread object, the current thread object enters the blocking state. When sleep expires or the synchronization lock is obtained, it returns to the ready state.
  • If the thread task completes/exits abnormally when the CPU is running the current thread object, the current thread object enters the death state.

Please add image description

Summarize

Multithreading GCD NSOperation NSOperationQueue NSThreadAs an important member of iOS multithreading, GCD provides reliable and diverse methods with more APIs. NSOperation is more concise, and NSThread is not used so often.

Multi-threaded programming is the focus of iOS, so review it diligently.

Guess you like

Origin blog.csdn.net/weixin_61639290/article/details/130904027