Linux线程

一个进程的所有线程可以访问该进程的组成部件,如文件描述符和内存。

每个线程都包含有表示执行环境所必需的信息,其中包括进程中标识线程的线程ID、一组寄存器值、栈、调度优先级和策略、信号屏蔽字、errno变量以及线程私有数据。而进程的所有信息对所有的线程是共享的,包括执行程序的代码、程序的全局内存和堆内存、栈以及文件描述符。

*  pthread_equal()—比较两个线程标识是否相同

#include <pthread.h>

int pthread_equal(pthread_t t1, pthread_t t2);

为什么不能使用 if (t1 == t2) 的方式比较两个线程标识符呢?因为你不知道 pthread_t 是什么类型的,所以永远不要自己直接操作它。

*  Pthread_self()—获取当前线程的id

#include <pthread.h>

pthread_t pthread_self(void);

*  pthread_create()—创建线程

#include <pthread.h>

int pthread_create(pthread_t *thread, const pthread_attr_t   *attr,

                          void *(*start_routine)   (void *), void *arg);

参数说明:

thread由函数回填的线程标识符,它来唯一的标识产生的新线程,后面我们只要需要操作新线程就需要用到它;

attr线程属性,使用 NULL,也就是使用默认属性。

start_routine线程的执行函数;入参是 void*,返回值是 void*,恭喜你,这两个值的类型都是百搭的,任何类型你都可以在这使用了。

arg传递给 start_routine void* 参数。

返回值:成功返回 0;失败返回 errno。为什么线程函数返回的是 errno 呢?因为在一些平台上 error 是全局变量,如果大家都使用同一个全局变量,在多线程的情况下就可能会出现竞争,所以 POSIX 的线程函数一般在失败的时候都是直接返回 errno 的,这样就避免了某些平台 errno 的缺陷了。

新线程和当前的线程是两个兄弟线程,他们是平等的,不是父子关系。

*  pthread_exit()—线程终止函数

pthread_join()—线程收尾函数

pthread_detach()—函数用于分离线程的收尾

#include <pthread.h>

void pthread_exit(void *retval);

int pthread_join(pthread_t thread, void **rval_ptr); //rval_ptr用于传出参数

int pthread_detach(pthread_t thread);

在线程执行函数中调用pthread_exit,作用是退出当前线程,并将返回值通过 retval 参数返回给调用 pthread_join(3) 函数的地方,如果不需要返回值可以传入 NULL

*  pthread_cancel()—取消同一进程中的其他线程

#include <pthread.h>

int pthread_cancel(pthread_t thread);

pthread_cancel()函数并不等待线程终止,它仅仅提出请求。

*  线程清理处理函数

#include <pthread.h>

void pthread_cleanup_push(void (*routine)(void *), void   *arg);

void pthread_cleanup_pop(int execute);

 

线程同步机制

u  互斥量mutex

状态:加锁和不加锁

通过休眠使进程或线程阻塞。

u  读写锁

状态:读模式下加锁、写模式下加锁和不加锁状态

多个线程可以同时占用有读模式下加锁状态。

u  自旋锁

自旋锁与互斥锁类似,但它不是通过休眠使进程或线程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。

自旋锁用在非抢占式内核中非常有用,而在用户层则很少用。

u  条件变量

组合:条件变量+互斥量

互斥量是用于上锁的,条件变量是用于等待的。

 

注意:编译POSIX线程程序时需要-pthread参数。

Ref

l  Linux线程

l  互斥量和读写

l  条件变量