线程

130 阅读3分钟

基本概念

  • 线程是轻量级的进程(LWP:Light Weight Process),在 Linux 环境下线程的本质仍是进程。

  • NPTL:Native POSIX Thread Library,是 Linux 线程的一个新实现。

  • 线程属性类型 pthread_attr_t

  • 一般情况下,main函数所在的线程我们称之为主线程(main线程),其余创建的线程称之为子线程。

线程系统调用

  • 创建线程

    • int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)
      • thread:传出参数,线程创建成功后,子线程的线程ID被写到该变量中。

      • attr : 设置线程的属性,一般使用默认值,NULL

      • start_routine : 函数指针,这个函数是子线程需要处理的逻辑代码

      • arg : 给第三个参数使用,传参

  • 获取线程ID

    • pthread_t pthread_self(void);
  • 比较两个线程ID是否相等

    • int pthread_equal(pthread_t t1, pthread_t t2);
      • 不同的操作系统,pthread_t 类型的实现不一样,有的是无符号的长整型,有的是使用结构体去实现的。
  • 终止线程

    • void pthread_exit(void *retval)
  • 回收子线程

    • int pthread_join(pthread_t thread, void **retval);
      • 回收子线程的资源
      • 这个函数是阻塞函数
      • 调用一次只能回收一个子线程
      • 一般在主线程中使用
  • 分离一个线程

    • int pthread_detach(pthread_t thread);
  • 线程取消(终止)

    • int pthread_cancel(pthread_t thread);
      • 取消某个线程,可以终止某个线程的运行,但是并不是立马终止,而是当子线程执行到一个取消点,线程才会终止。
      • 取消点:系统规定好的一些系统调用,我们可以粗略的理解为从用户区到内核区的切换,这个位置称之为取消点。
  • 初始化线程属性变量

    • int pthread_attr_init(pthread_attr_t *attr);
  • 释放线程属性的资源

    • int pthread_attr_destroy(pthread_attr_t *attr);
  • 获取线程分离的状态属性

    • int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);
  • 设置线程分离的状态属性

    • int pthread_attr_setdetachstate(pthread_attr_t *attr, intdetachstate);

线程同步

互斥量

  • 互斥量 mutex
  • 互斥量的类型 pthread_mutex_t
  • 两种状态
    • 已锁定(locked)
    • 未锁定(unlocked)

互斥量系统调用

  • 初始化互斥量

    • int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr)

    • mutex : 需要初始化的互斥量变量

    • attr : 互斥量相关的属性,一般可以传递NULL

      • restrict : C语言的修饰符,被修饰的指针,不能由另外的一个指针进行操作。
  • 释放互斥量的资源

    • int pthread_mutex_destroy(pthread_mutex_t *mutex)
  • 加锁:阻塞

    • int pthread_mutex_lock(pthread_mutex_t *mutex)

      • 阻塞的,如果有一个线程加锁了,那么其他的线程只能阻塞等待
  • 尝试加锁 :非阻塞

    • int pthread_mutex_trylock(pthread_mutex_t *mutex)

      • 如果加锁失败,不会阻塞,会直接返回。
  • 解锁

    • int pthread_mutex_unlock(pthread_mutex_t *mutex)

读写锁

  • 读写锁的类型 pthread_rwlock_t
  • 允许多个读出,但只允许一个写入
  • 特点:
    • 如果有其它线程读数据,则允许其它线程执行读操作,但不允许写操作。
    • 如果有其它线程写数据,则其它线程都不允许读、写操作。
    • 写是独占的,写的优先级高。

读写锁系统调用

  • int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr)
  • int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
  • int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
  • int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
  • int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
  • int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
  • int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)

条件变量

  • 不是锁,与互斥锁搭配使用。
  • 当条件满足时,阻塞/解除阻塞线程。
  • 条件变量的类型 pthread_cond_t

条件变量系统调用

  • int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr)

  • int pthread_cond_destroy(pthread_cond_t *cond)

  • 等待,调用了该函数,线程会阻塞

    • int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
      • 当这个函数调用阻塞的时候,会对互斥锁进行解锁,当不阻塞的,继续向下执行,会重新加锁。
  • 等待多长时间,调用了这个函数,线程会阻塞,直到指定的时间结束(不阻塞了)

    • int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime)
  • 唤醒一个或者多个等待的线程

    • int pthread_cond_signal(pthread_cond_t *cond)
  • 唤醒所有的等待的线程

    • int pthread_cond_broadcast(pthread_cond_t *cond)

信号量

  • 信号量的类型 sem_t

信号量系统调用

  • 初始化信号量
    • int sem_init(sem_t *sem, int pshared, unsigned int value)
      • sem : 信号量变量的地址
      • pshared : 0 用在线程间 ,非0 用在进程间
      • value : 信号量中的值
  • 释放资源
    • int sem_destroy(sem_t *sem)
  • 对信号量加锁,调用一次对信号量的值-1;如果值为0,就阻塞
    • int sem_wait(sem_t *sem)
  • 对信号量解锁,调用一次对信号量的值+1
    • int sem_post(sem_t *sem)
  • int sem_getvalue(sem_t *sem, int *sval)
  • int sem_trywait(sem_t *sem)
  • int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout)