线程API

1. 创建线程

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                   void *(*start_routine) (void *), void *arg);

参数

  • thread 属于结果参数,函数结束时,返回线程ID并存储到thread中
  • attr 设置线程的属性,一般为NULL,表示采用线程默认属性
  • start_routine 回调函数,线程要执行的函数
  • arg 回调函数 start_routine() 执行时的参数。

返回值

  • 成功 0
  • 失败 非0

2. 线程标识

#include <pthread.h>

int pthread_equal(pthread_t t1, pthread_t t2);
pthread_t pthread_self(void);

函数

  • pthread_equal 判断线程ID是否相等
  • pthread_self 返回调用线程的线程ID

3. 线程退出

3.1 线程自行退出

#include <pthread.h>

void pthread_exit(void * retval);

retval 记录线程的退出信息,记录方式:

  1. 不可以使用线程的局部变量。
  2. NULL 仅退出,不返回信息
  3. 使用全局变量
  4. 动态分配内存
  5. 字符串常量

3.2 其他线程取消

#include <pthread.h>

int pthread_cancel(pthread_t thread);
int pthread_setcancelstate(int state, int *oldstate);

函数

  • pthread_cancel 取消thread的线程
  • pthread_setcancelstate : 设置线程取消属性
    • state:
      • PTHREAD_CANCEL_ENABLE : 线程可以被取消
      • PTHREAD_CANCEL_DISABLE : 线程不可以被取消
    • oldstate : 保持上一次取消属性的状态。

4. 连接(释放)线程

join其他线程的时候会调用 __nptl_free_tcb (pd); 释放退出线程的资源。

但是NPTL模型会缓存该线程的地址空间,并不会立即 munmap ,后创建的线程会复用这块内存地址,避免了频繁的 mmapmunmap ,所以

  • 使用 pthread_join 连接退出线程,后面启动的线程会复用前面 joined 栈内存空间
  • 如果不使用 pthread_join 连接线程,那么新的线程会分配新的栈空间,从而导致内存泄漏。
#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);

retval : 存放线程返回值的地址

5. 线程分离

pthread_detach 用来设置一个线程的属性为分离属性

#include <pthread.h>

int pthread_detach(pthread_t thread);

6. 线程同步

6.1 互斥锁(mutex)

#include <pthread.h>

/* 初始化线程互斥锁 */
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutex_attr_t *mutexattr);
/* 阻塞加锁 */
int pthread_mutex_lock(pthread_mutex *mutex);
/* 非阻塞加锁 */
int pthread_mutex_trylock( pthread_mutex_t *mutex);
/* 解锁 */
int pthread_mutex_unlock(pthread_mutex *mutex);
/* 销毁锁 */
int pthread_mutex_destroy(pthread_mutex *mutex);

6.2 条件变量(cond)

#include <pthread.h>
/* 初始化条件变量 */
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *cond_attr);
/* 无条件等待 */
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
/* 计时条件 */
int pthread_cond_timewait(pthread_cond_t *cond,pthread_mutex *mutex,const timespec *abstime);
/* 激活一个等待该条件的线程 */
int pthread_cond_signal(pthread_cond_t *cond);
/* 激活所有等待线程 */
int pthread_cond_broadcast(pthread_cond_t *cond);
/* 销毁条件变量 */
int pthread_cond_destroy(pthread_cond_t *cond);

6.3 读写锁

  • 如果一个线程用读锁锁定了临界区,那么其他线程也可以用读锁来进入临界区,这样就可以多个线程并行操作。但这个时候,如果再进行写锁加锁就会发生阻塞,写锁请求阻塞后,后面如果继续有读锁来请求,这些后来的读锁都会被阻塞!这样避免了读锁长期占用资源,防止写锁饥饿!
  • 如果一个线程用写锁锁住了临界区,那么其他线程不管是读锁还是写锁都会发生阻塞!
#include <pthread.h>
/* 初始读写锁 */
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);

int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);

int pthread_rwlock_timedrdlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *restrict rwlock, const struct timespec *restrict abs_timeout);
/* 销毁锁 */
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
posted @ 2025-07-29 08:50  星空丶star  阅读(15)  评论(0)    收藏  举报