27.1线程创建

  1. //创建线程
  2. int pthread_create(pthread_t *thread,
  3. const pthread_attr_t *attr,
  4. void (*start_routine)(void*),
  5. void *arg);

  • thread-local变量
  1. __thread int x;
  2. __thread char *s;

类似这种以__thread定义的变量是线程本地变量 会在创建的每一个线程中都保留一个副本

27.2线程完成

  1. //等待线程结束
  2. int pthread_join(pthread_t thread,void **value_ptr)
  3. //注意其第二个参数的类型是pointer to pointer

pthread_join()的第二个参数是一个指针,指向希望得到的返回值,如果不需要返回值,那么也可以传入NULL

27.3 锁

  1. int pthread_mutex_lock(pthread_mutex_t *mutex);
  2. int pthread_mutex_unlock(pthread_mutex_t *mutex);

如果意识到有一段代码是一个临界区,那么就需要通过锁来保护


所有的锁必须正确初始化 以确保他们具有正确的值 并在锁和解锁被调用时按照需要工作

初始化锁:

  • ①使用PTHREAD_MUTEX_INITIALIZER
  1. pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER
  • ②动态方法 调用pthread_mutex_init()
  1. int rc=pthread_mutex_init(&lock,NULL);
  2. assert(rc==0) //alwasy check success!

第一个参数是锁本身的地址,第二个参数是可选属性

27.4 条件变量

当线程之间必须要发生某种信号时 如果一个线程在等待另一个线程继续执行某些操作,条件变量很有用

  1. int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);//使调用线程进入休眠状态
  2. int pthread_cond_signal(pthread_cond_t *cond);

要使用条件变量 必须另外有一个与此条件相关的锁 在调用函数时 要持有这个锁


典型用法:

  1. pthread_mutex_t lock=PTHREAD_MUTEX_INITIALIZER;
  2. pthread_cond_t cond=PTHREAD_COND_INITIALIZER;
  3. pthread_mutex_lock(&lock);
  4. while(ready==0)
  5. pthread_cond_wait(&cond,&lock);
  6. pthread_mutex_unlock(&lock);

在初始化相关锁和条件后 一个线程检查变量ready是否已经被设置为0意外的值 如果没有 就调用等待函数休眠 直到其他线程唤醒它


唤醒线程的代码:

  1. pthread_mutex_lock(&lock,NULL);
  2. ready=1;
  3. pthread_cond_signal(&cond);
  4. pthread_mutex_unlock(&lock);
  • 等待调用将锁作为第二个参数 而信号调用只需要一个参数:因为等待调用除了使线程进入睡眠状态外,还会让调用者在睡眠的时候释放锁(不然其他线程怎么获得锁 修改临界区内容从而唤醒该线程捏?)
  • 在被唤醒之后、返回之前,pthread_cond_wait()会重新获得该锁 确保整个过程都持有锁

每个线程都有自己的栈:线程的局部变量是线程私有的。线程之间共享数据,值要在堆区或者其他全局可访问的位置:e.g. ①刚刚的例子中ready就是全局变量 ②malloc出来的动态内存是位于堆区的