简介
线程(Thread)就是运行在进程上下文中的逻辑流,每个线程都有自己独立的上下文,所有运行在同一个进程中的线程共享该进程的整个虚拟地址空间。
我自己时常简单理解为线程是最小的可调度单位,进程是最小的持有资源单位。
-
线程
- 线程上下文
- 唯一的整数线程ID
- 栈
- 栈指针
- 程序计数器
- 通用目的寄存器
- 条件码
多线程的执行模型和多进程的执行模型是相似的。每个进程开始生命周期时都是单一线程,整个线程成为主线程。某一时刻之后,主线程创建一个对等线程。
- 线程的上下文切换要比进程上下文切换快得多
- 进程是按照父子层次来组织的,线程是对等的,一个线程可以杀死任意对等线程
在Linux中进程和线程的描述结构是一致的
-
线程状态
- 新建 New
- 就绪 Ready
- 运行 Running
- 终止 Terminated
- 浅度睡眠 Interruptible
- 深度睡眠 Uninterruptible
- 停止 Stopped
iOS线程调度的库如图,有由BSD提供的Pthreads,Kernel提供的mach_thread,基于Pthreads封装的NSThread,以及NSOperation/NSOperationQueue和Libdispatch库实现的GCD.
Posix线程
Posix线程(Pthreads)是在C程序中处理线程的一个标准接口。允许程序创建、杀死和回收线程,与对等线程安全地共享数据,还可以通知对等线程系统状态的变化。
线程操作
创建线程
可以使用pthread_attr_t线程属性来创建pthread,如果使用默认线程属性的话,传NULL即可
int pthread_create(pthread_t _Nullable * _Nonnull __restrict,
const pthread_attr_t * _Nullable __restrict,
void * _Nullable (* _Nonnull)(void * _Nullable),
void * _Nullable __restrict);
- (void)createThread {
pthread_t thread;
pthread_create(&thread, NULL, run, NULL);
pthread_detach(thread);
}
void *run(void *param) {
NSLog(@"%@", [NSThread currentThread]);
return NULL;
}
线程属性
应用场景
// 声明 pthread_attr_t
pthread_attr_t attr;
// 初始化
pthread_attr_init(&attr);
// 设置
pthread_attr_setscope(&attr, int); // 作用域
pthread_attr_setstack(&attr, void * _Nonnull, size_t); // 栈
pthread_attr_setguardsize(&attr, size_t); // 栈末尾的警戒缓冲区大小
pthread_attr_setstackaddr(&attr, void * _Nonnull); // 栈地址
pthread_attr_setstacksize(&attr, size_t); // 栈大小
pthread_attr_setschedparam(&attr, const struct sched_param *restrict _Nonnull); // 调度参数
pthread_attr_setdetachstate(&attr, int); // 分离状态
pthread_attr_setschedpolicy(&attr, int); // 调度策略
pthread_attr_setinheritsched(&attr, int); // 继承
pthread_attr_set_qos_class_np(&attr, qos_class_t __qos_class, int __relative_priority); // 分配 QoS 类
// 创建线程时将 attr 地址传入
// pthread_create(&thread, &attr, ...);
// 使用完毕销毁
pthread_attr_destroy(&attr);
取消线程
发送成功并不意味着thread会终止
int pthread_cancel(pthread_t) __DARWIN_ALIAS(pthread_cancel);
终止线程
线程显示退出
void pthread_exit(void * _Nullable) __dead2;
回收已终止线程的资源
以阻塞的方式等待thread指定的线程结束,当函数返回时,被等待线程的资源被收回。如果线程已经结束,该函数会立即返回。thread指定的线程必须是joinable的
int pthread_join(pthread_t , void * _Nullable * _Nullable)
__DARWIN_ALIAS_C(pthread_join);
锁
互斥锁
sleep-waiting类型的锁
MUTEX ROUTINES
int pthread_mutexattr_destroy(pthread _ mutexattr _ t *attr)
Destroy a mutex attributes object.
int pthread_mutexattr_init(pthread _ mutexattr _ t *attr)
Initialize a mutex attributes object with default val-ues. values.
ues.
int pthread_mutex_destroy(pthread _ mutex _ t *mutex)
Destroy a mutex.
int pthread_mutex_init(pthread _ mutex _ t *mutex, const pthread _ mutexattr _ t
*attr)
Initialize a mutex with specified attributes.
int pthread_mutex_lock(pthread _ mutex _ t *mutex)
Lock a mutex and block until it becomes available.
int pthread_mutex_trylock(pthread _ mutex _ t *mutex)
Try to lock a mutex, but don't block if the mutex is
locked by another thread, including the current
thread.
int pthread_mutex_unlock(pthread _ mutex _ t *mutex)
Unlock a mutex.
条件变量
线程进入等待列表,等待信号的唤醒
CONDITION VARIABLE ROUTINES
int pthread_condattr_init(pthread _ condattr _ t *attr)
Initialize a condition variable attributes object with
default values.
int pthread_condattr_destroy(pthread _ condattr _ t *attr)
Destroy a condition variable attributes object.
int pthread_cond_broadcast(pthread _ cond _ t *cond)
Unblock all threads currently blocked on the specified
condition variable.
int pthread_cond_destroy(pthread _ cond _ t *cond)
Destroy a condition variable.
int pthread_cond_init(pthread _ cond _ t *cond, const pthread _ condattr _ t
*attr)
Initialize a condition variable with specified
attributes.
int pthread_cond_signal(pthread _ cond _ t *cond)
Unblock at least one of the threads blocked on the
specified condition variable.
int pthread_cond_timedwait(pthread _ cond _ t *cond, pthread _ mutex _ t *mutex,
const struct timespec *abstime)
Wait no longer than the specified time for a condition
and lock the specified mutex.
int pthread_cond_wait(pthread _ cond _ t *, pthread _ mutex _ t *mutex)
Wait for a condition and lock the specified mutex.
读写锁
写写互斥,读写互斥,读读并发
READ/WRITE LOCK ROUTINES
int pthread_rwlock_destroy(pthread _ rwlock _ t *lock)
Destroy a read/write lock object.
int pthread_rwlock_init(pthread _ rwlock _ t *lock, const
pthread _ rwlockattr _ t *attr)
Initialize a read/write lock object.
int pthread_rwlock_rdlock(pthread _ rwlock _ t *lock)
Lock a read/write lock for reading, blocking until the
lock can be acquired.
int pthread_rwlock_tryrdlock(pthread _ rwlock _ t *lock)
Attempt to lock a read/write lock for reading, without
blocking if the lock is unavailable.
int pthread_rwlock_trywrlock(pthread _ rwlock _ t *lock)
Attempt to lock a read/write lock for writing, without
blocking if the lock is unavailable.
int pthread_rwlock_unlock(pthread _ rwlock _ t *lock)
Unlock a read/write lock.
int pthread_rwlock_wrlock(pthread _ rwlock _ t *lock)
Lock a read/write lock for writing, blocking until the
lock can be acquired.
int pthread_rwlockattr_destroy(pthread _ rwlockattr _ t *attr)
Destroy a read/write lock attribute object.
int pthread_rwlockattr_getpshared(const pthread _ rwlockattr _ t *attr, int
*pshared)
Retrieve the process shared setting for the read/write
lock attribute object.
int pthread_rwlockattr_init(pthread _ rwlockattr _ t *attr)
Initialize a read/write lock attribute object.
int pthread_rwlockattr_setpshared(pthread _ rwlockattr _ t *attr, int
pshared)
Set the process shared setting for the read/write lock
attribute object.
private var moduleLock = pthread_rwlock_t()
pthread_rwlock_init(&moduleLock, nil)
private var _modules: [String: DuConfigModule] = [:]
private var modules: [String: DuConfigModule] {
set {
pthread_rwlock_wrlock(&moduleLock)
_modules = newValue
pthread_rwlock_unlock(&moduleLock)
}
get {
pthread_rwlock_rdlock(&moduleLock)
let modules = _modules
pthread_rwlock_unlock(&moduleLock)
return modules
}
}
自旋锁
busy-waiting类型的锁
Barrier
所有线程都达到这个栅栏时,栅栏才会放行,否则到达此处的线程会被阻塞
NSThread
变量
类变量
class var current: Thread { get }
class var callStackReturnAddresses: [NSNumber] { get }
class var callStackSymbols: [String] { get }
class var isMainThread: Bool { get }
class var main: Thread { get }
实例变量
var threadDictionary: NSMutableDictionary { get }
var threadPriority: Double
var qualityOfService: QualityOfService
var name: String?
var stackSize: Int
var isMainThread: Bool { get }
var isExecuting: Bool { get }
var isFinished: Bool { get }
var isCancelled: Bool { get }
方法
初始化方法
public convenience init(target: Any, selector: Selector, object argument: Any?)
public convenience init(block: @escaping () -> Void)
类方法
class func detachNewThread(_ block: @escaping () -> Void)
class func detachNewThreadSelector(_ selector: Selector, toTarget target: Any, with argument: Any?)
class func isMultiThreaded() -> Bool
class func sleep(until date: Date)
class func sleep(forTimeInterval ti: TimeInterval)
class func exit()
class func threadPriority() -> Double
class func setThreadPriority(_ p: Double) -> Bool
实例方法
func cancel()
func start()
func main()
源码实现
GNUStep中NSThread实现
- (void) start
{
pthread_attr_t attr;
// 省略Exception处理
/* Make sure the notification is posted BEFORE the new thread starts.
*/
gnustep_base_thread_callback();
/* The thread must persist until it finishes executing.
*/
RETAIN(self);
/* Mark the thread as active while it's running.
*/
_active = YES;
errno = 0;
pthread_attr_init(&attr);
/* Create this thread detached, because we never use the return state from
* threads.
*/
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/* Set the stack size when the thread is created. Unlike the old setrlimit
* code, this actually works.
*/
if (_stackSize > 0)
{
pthread_attr_setstacksize(&attr, _stackSize);
}
if (pthread_create(&pthreadID, &attr, nsthreadLauncher, self))
{
DESTROY(self);
[NSException raise: NSInternalInconsistencyException format: @"Unable to detach thread (last error %@)", [NSError _last]];
}
}
应用
显式创建
- (void)createNSThread {
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start];
//或者 [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
}
- (void)run {
NSLog(@"run %@", [NSThread currentThread]);
}
隐式创建
[self performSelectorInBackground:@selector(run) withObject:nil];
Mach_Thread
thread_info
kern_return_t thread_info
(
thread_inspect_t target_act,
thread_flavor_t flavor,
thread_info_t thread_info_out,
mach_msg_type_number_t *thread_info_outCnt
);
thread_basic_info
数据结构
struct thread_basic_info {
time_value_t user_time; /* user run time */
time_value_t system_time; /* system run time */
integer_t cpu_usage; /* scaled cpu usage percentage */
policy_t policy; /* scheduling policy in effect */
integer_t run_state; /* run state (see below) */
integer_t flags; /* various flags (see below) */
integer_t suspend_count; /* suspend count for thread */
integer_t sleep_time; /* number of seconds that thread
* has been sleeping */
};
usage_scale
/*
* Scale factor for usage field.
*/
#define TH_USAGE_SCALE 1000
run_state
/*
* Thread run states (state field).
*/
#define TH_STATE_RUNNING 1 /* thread is running normally */
#define TH_STATE_STOPPED 2 /* thread is stopped */
#define TH_STATE_WAITING 3 /* thread is waiting normally */
#define TH_STATE_UNINTERRUPTIBLE 4 /* thread is in an uninterruptible
* wait */
#define TH_STATE_HALTED 5 /* thread is halted at a
* clean point */
flags
/*
* Thread flags (flags field).
*/
#define TH_FLAGS_SWAPPED 0x1 /* thread is swapped out */
#define TH_FLAGS_IDLE 0x2 /* thread is an idle thread */
#define TH_FLAGS_GLOBAL_FORCED_IDLE 0x4 /* thread performs global forced idle */
应用场景
CPU使用率计算
单核CPU使用率需要再除以CPU活动内核数
thread_basic_info_t basic_info_th = (thread_basic_info_t)thinfo;
if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float) TH_USAGE_SCALE * 100.0;
}
thread_identifier_info
数据结构
struct thread_identifier_info {
uint64_t thread_id; /* system-wide unique 64-bit thread id */
uint64_t thread_handle; /* handle to be used by libproc */
uint64_t dispatch_qaddr; /* libdispatch queue address */
};
应用场景
获取线程对应的队列名称
kr = thread_info((thread_t)thread, THREAD_IDENTIFIER_INFO, info, &inOutSize);
thread_identifier_info_t idInfo = (thread_identifier_info_t)info;
dispatch_queue_t* dispatch_queue_ptr = (dispatch_queue_t*)idInfo->dispatch_qaddr;
dispatch_queue_t dispatch_queue = *dispatch_queue_ptr;
const char* queue_name = dispatch_queue_get_label(dispatch_queue);
thread_extended_info
数据结构
struct thread_extended_info { // same as proc_threadinfo (from proc_info.h) & proc_threadinfo_internal (from bsd_taskinfo.h)
uint64_t pth_user_time; /* user run time */
uint64_t pth_system_time; /* system run time */
int32_t pth_cpu_usage; /* scaled cpu usage percentage */
int32_t pth_policy; /* scheduling policy in effect */
int32_t pth_run_state; /* run state (see below) */
int32_t pth_flags; /* various flags (see below) */
int32_t pth_sleep_time; /* number of seconds that thread */
int32_t pth_curpri; /* cur priority*/
int32_t pth_priority; /* priority*/
int32_t pth_maxpriority; /* max priority*/
char pth_name[MAXTHREADNAMESIZE]; /* thread name, if any */
};
thread_act
thread_get_state
数据结构
kern_return_t thread_get_state
(
thread_read_t target_act,
thread_state_flavor_t flavor,
thread_state_t old_state,
mach_msg_type_number_t *old_stateCnt
);
应用场景
获取线程调用栈
#include "backtrace.h"
#include <stdio.h>
#include <stdlib.h>
#include <machine/_mcontext.h>
#if defined __i386__
#define THREAD_STATE_FLAVOR x86_THREAD_STATE32
#define THREAD_STATE_COUNT x86_THREAD_STATE32_COUNT
#define __framePointer __ebp
#elif defined __x86_64__
#define THREAD_STATE_FLAVOR x86_THREAD_STATE64
#define THREAD_STATE_COUNT x86_THREAD_STATE64_COUNT
#define __framePointer __rbp
#elif defined __arm__
#define THREAD_STATE_FLAVOR ARM_THREAD_STATE
#define THREAD_STATE_COUNT ARM_THREAD_STATE_COUNT
#define __framePointer __r[7]
#elif defined __arm64__
#define THREAD_STATE_FLAVOR ARM_THREAD_STATE64
#define THREAD_STATE_COUNT ARM_THREAD_STATE64_COUNT
#define __framePointer __fp
#else
#error "Current CPU Architecture is not supported"
#endif
int df_backtrace(thread_t thread, void** stack, int maxSymbols) {
_STRUCT_MCONTEXT machineContext;
mach_msg_type_number_t stateCount = THREAD_STATE_COUNT;
kern_return_t kret = thread_get_state(thread, THREAD_STATE_FLAVOR, (thread_state_t)&(machineContext.__ss), &stateCount);
if (kret != KERN_SUCCESS) {
return 0;
}
int i = 0;
#if defined (__arm__) || defined (__arm64__)
stack[i] = (void *)machineContext.__ss.__lr;
++i;
#endif
void **currentFramePointer = (void **)machineContext.__ss.__framePointer;
while (i < maxSymbols && currentFramePointer) {
void **previousFramePointer = *currentFramePointer;
if (!previousFramePointer) {
break;
}
stack[i] = *(currentFramePointer + 1);
currentFramePointer = previousFramePointer;
++i;
}
return i;
}
线程操作
thread_suspend
thread_resume
thread_abort
thread_abort_safely
应用场景
获取所有线程堆栈和栈内存对象的时候,挂起所有线程
void ksmc_suspendEnvironment()
{
#if KSCRASH_HAS_THREADS_API
KSLOG_DEBUG("Suspending environment.");
kern_return_t kr;
const task_t thisTask = mach_task_self();
const thread_t thisThread = (thread_t)ksthread_self();
if((kr = task_threads(thisTask, &g_suspendedThreads, &g_suspendedThreadsCount)) != KERN_SUCCESS)
{
KSLOG_ERROR("task_threads: %s", mach_error_string(kr));
return;
}
for(mach_msg_type_number_t i = 0; i < g_suspendedThreadsCount; i++)
{
thread_t thread = g_suspendedThreads[i];
if(thread != thisThread && !isThreadInList(thread, g_reservedThreads, g_reservedThreadsCount))
{
if((kr = thread_suspend(thread)) != KERN_SUCCESS)
{
// Record the error and keep going.
KSLOG_ERROR("thread_suspend (%08x): %s", thread, mach_error_string(kr));
}
}
}
KSLOG_DEBUG("Suspend complete.");
#endif
}
异常端口
详情请参见我之前的两篇博客《APM - iOS Crash监控 原理浅析》和《APM - iOS Crash监控 XNU 异常处理》
thread_set_exception_ports
thread_get_exception_ports
thread_swap_exception_ports
NSOperation/NSOperationQueue
详情请参见我之后的博客《NSOperation/NSOperationQueue源码解析》
GCD
详情请参见我之后的博客《libdispatch源码解析》
其他
Pthread和mach_thread如何转换?
func machThread(from thread: Thread) -> thread_t {
var count: mach_msg_type_number_t = 0
var threads: thread_act_array_t!
guard task_threads(mach_task_self_, &(threads), &count) == KERN_SUCCESS else {
return mach_thread_self()
}
if thread.isMainThread {
return threads[0]
}
let originName = thread.name
defer {
thread.name = originName
}
let newName = String(Int(Date.init().timeIntervalSince1970))
thread.name = newName
for i in 0..<count {
let machThread = threads[Int(i)]
if let p_thread = pthread_from_mach_thread_np(machThread) {
var name: [Int8] = Array<Int8>(repeating: 0, count: 128)
pthread_getname_np(p_thread, &name, name.count)
if thread.name == String(cString: name) {
return machThread
}
}
}
return mach_thread_self()
}
NSThread是基于Pthread封装的吗?
- 从GNUStep的源码实现来看,是调用了Pthreads的方法
- 从Time Profiler来看,最终调用函数是_pthread_start
- 但是Hook了pthread_create之后,发现通过NSThread创建的时候并没有调用pthread_create
thread_self需要注意什么?
thread_t thread_self()
{
thread_t thread_self = mach_thread_self();
mach_port_deallocate(mach_task_self(), thread_self);
return thread_self;
}
引用
iOS Manual Pages:developer.apple.com/library/arc…