您的位置:首页 > 运维架构 > Linux

Linux系统编程学习之《线程》

2013-08-29 21:08 106 查看
今天来总结一下Linux下的线程方面知识:

和进程相似,线程也有系统内的标识符,它的类型是pthread_t(进程是pid_t)

线程标识符只在同一进程内有效,不同进程之间可以有相同的线程标识符

1.线程标识符

我们先来看看有关线程标识符的函数

/*
* #include <pthread.h>
* int pthread_equal(pthread_t tid1,pthread_t tid2);
* 比较tid1和tid2两个线程是否是同一个线程(不同进程可有相同线程ID)
* 是统一个返回非0,不是返回0
* ---------------------------------------------------
* pthread_t pthread_self(void);
* 返回线程的ID
*/

2.创建线程

Linux下创建线程比较简单,只要调用一个函数就可以了

/*
* #include <pthread.h>
* int pthread_create(pthread_t * restrict tidp,const pthread_attr_t * restrict attr,
*             void * (*start_rtn)(void),void * restrict arg);
* tidp:保存新线程ID的指针
* attr:创建的线程的属性,NULL为默认属性
* (*start_rtn)(void):线程启动要要执行的函数,声明格式是:void * funcname(void * arg);
* arg:线程执行函数的参数,NULL为不传参数
*/


3.终止线程

终止线程有三种终止方式:1.线程从启动例程中返回   2.线程被同一进程中的其他线程取消   3.线程自己调用pthread_exit

/*
* #include <pthread.h>
* void pthread_exit(void * rval_ptr);
* 线程自己调用,终止线程运行,直接返回,返回码保存在rval_ptr中
* --------------------------------------
* int pthread_join(pthread_t thread,void ** rval_ptr);
* 同一进程中的其他线程可以调用此函数,等待指定线程结束,并获取它的返回码
* 等待过程将阻塞调用此函数的线程
* --------------------------------------
* int pthread_cancel(pthread_t tid);
* 成功返回0,出错返回错误编号
* 该函数用于线程提出请求终止同一进程中的其他线程,不过被请求线程可忽略此请求
*/


4.清理线程


我们知道,进程退出是可用atexit函数注册一些清理处理的函数,线程也一样可以调用一些清理函数

/*
* #include <pthread.h>
* void pthread_cleanup_push(void (*rtn)(void *),void * arg);
* (*rtn)(void *):清理处理函数,定义格式:void funcname(void * arg);
* arg:传给清理处理函数的参数
* -----------------------------------
* void pthread_cleanup_pop(int execute);
* execute:非0则执行清理函数,0则不执行
* -----------------------------------
* 上述两个函数要在作用域{}内配对使用,否则可能会出错
*/

5.分离线程

线程有一个分离状态,使得调用pthread_join函数无法等待到它的终止状态,线程的分离状态可以在创建时确立,也可以调用函数

/*
* #include <pthread.h>
* int pthread_detach(pthread_t tid);
* 成功返回0,出错返回错误编号
* 该函数使线程进入分离状态
*/


6.线程同步之互斥量(锁)


当有多个线程同时访问同一个变量的时候,就可能会出现数据读写不同步的问题,这就需要我们设置线程的同步机制

作为同步机制,最重要的当然就是锁了,Linux中的锁变量类型是pthread_mutex_init

/*
* #include <pthread.h>
* int pthread_mutex_init(pthread_mutex_t * restrict mutex,const pthread_mutexattr_t * restrict attr);
* ----------------------------------------
* mutex:锁变量
* attr:锁的属性,NULL为默认属性
* ----------------------------------------
* int pthread_mutex_destroy(pthread_mutex_t * mutex);
* ----------------------------------------
* 要销毁的锁变量
* ----------------------------------------
* 两个函数成功返回0,出错返回错误编号
* ----------------------------------------
* 锁的变量类型是pthread_mutex_t,要使用锁之前,先要对其进行初始化
* 可以把它设置为常量PTHREAD_MUTEX_INITALIZER(只对静态分配的互斥锁有效)
* 其他的就要调用pthread_mutex_init函数
* 如果是动态分配的互斥锁(如调用malloc函数)
* 则在释放内存前需要调用pthread_mutex_destroy函数销毁
* ----------------------------------------
*/

7.线程同步之互斥量(锁)加锁

在互斥锁初始化后,我们需要调用一些函数才可以实现真正的加锁行为

/*
* #include <pthread.h>
* int pthread_mutex_lock(pthread_mutex_t * mutex);
* int pthread_mutex_trylock(pthread_mutex_t * mutex);
* int pthread_mutex_unlock(pthread_mutex_t * mutex);
* ---------------------------------
* 三个函数成功返回0,出错返回错误编号
* mutex是欲操作的锁变量
* pthread_mutex_lock对于mutex未加锁,则直接加锁进入下一步骤
* 如果mutex已被加锁,则线程会被阻塞,一致等待锁被释放了才进入锁
* pthread_mutex_trylock对于mutex未枷锁,则直接加锁进入下一步骤,返回0
* 如果mutex已被加锁,则线程不会被阻塞,加锁失败,返回EBUSY
* 无论哪种加锁方式,释放锁同一调用pthread_mutex_unlock函数
* ---------------------------------
*/

8.线程同步之读写锁

除了上述的互斥锁外,Linux还支持读写锁,读写锁也程共享-独占锁;

当读写锁以读模式锁住时,它是以共享模式锁住的;当它以写模式锁住时,它是以独占模式锁住的

读写锁的变量类型是pthread_rwlock_t,读写锁只可以用调用函数初始化方式初始化锁

/*
* #include <pthread.h>
* int pthread_rwlock_init(pthread_rwlock_t * restrict rwlock,const pthread_rwlockattr_t * restrict attr);
* ----------------------------------------
* rwlock:读写锁变量
* attr:读写锁属性,NULL为默认属性
* ----------------------------------------
* int pthread_rwlock_destroy(pthread_rwlock_t * rwlock); //rwlock为欲销毁的读写锁变量
* ----------------------------------------
* 两个函数成功返回0,粗错返回错误编号
*/

9.线程同步之读写锁加锁

了解了如何创建、初始、销毁读写锁后,现在就要了解如何对对写锁进行加锁

正如前面所说,读写锁有两种加锁方式,读锁加锁或写锁加锁

/*
* #include <pthread.h>
* int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock);  //加读锁
* int pthread_rwlock_wrlock(pthread_rwlock_t * rwlock);  //加写锁
* int pthread_rwlock_unlock(pthread_rwlock_t * rwlock);  //解除锁
* 所有函数:成功返回0,出错返回错误编号
* ------------------------------------------
* 加读锁时,如果没有被加写锁,则允许进入,否则阻塞
* 加写锁时,要当前锁没有任何锁状态才进入,否则阻塞等待
* 读锁写锁使用完毕后都要调用unlock函数解除锁状态
* ------------------------------------------
* int pthread_rwlock_tryrdlock(pthread_rwlock_t * rwlock);  //尝试加读锁
* int pthread_rwlock_tryrwlock(pthread_rwlock_t * rwlock);  //尝试加写锁
* ------------------------------------------
* 如果成功获取锁,则进入,函数返回0
* 否则,返回出错EBUSY,但并不阻塞等待
*/

10.线程同步之条件变量

条件变量是线程同步的另一种同步机制。条件变量与互斥量一起使用时,允许线程以无竞争的方式等待特定的条件发生

条件变量的数据类型是pthread_cond_t,有两种初始化方式

一种把PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,如果是动态分配的,则调用pthread_cond_init哈数进行初始化

/*
* #include <pthread.h>
* int pthread_cond_init(pthread_cond_t * restrict cond,pthread_condaddr_t * restrict attr);
* int pthread_cond_destroy(pthread_cond_t * cond); //cond为条件变量
* 两个函数:成功返回0,出错返回错误编号
* 在init函数中,如果要传递NULL给attr,则创建默认的条件变量
*/

11.线程同步之条件变量的使用

在初始化好条件变量后,我们现在要使用它了,使用的方法是调用如下函数:

/*
* #include <pthread.h>
* int pthread_cond_wait(pthread_cond_t * restrict cond,pthread_mutex_t * restrict mutex); //对等待事件出现,再加互斥锁
* int pthread_cond_timewait(pthread_cond_t * restrict cond,
* pthread_mutex_t * restrict mutex,const struct timespec * restrict timeout); //跟上面函数类似,不过等待绝对时间(即现在时间+需等待时间)
* 两个函数成功返回0,出错返回错误编号
* -------------------------------------------
* int pthread_cond_signal(pthread_cond_t * cond); //唤醒等待该条件变量的某个线程
* int pthread_cond_broadcast(pthread_cond_t * cond); //唤醒等待该条件变量的全部线程
* -------------------------------------------
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息