Chinaunix首页 | 论坛 | 博客
  • 博客访问: 253532
  • 博文数量: 44
  • 博客积分: 1052
  • 博客等级: 少尉
  • 技术积分: 742
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-17 16:51
文章分类

全部博文(44)

文章存档

2013年(7)

2012年(14)

2011年(23)

分类: LINUX

2013-08-18 23:30:53

线程

介绍线程的相关概念,以及相关函数。

1:在一个进程中,可以创建多个线程,各个线程共享使用进程的一些资源,同时各个线程又有自己的特定的资源。
关于线程主要考虑的就是线程的创建与同步

2:线程有一个自己的执行上下文,其中包括:
    (1)线程ID
    (2)一组寄存器值
    (3)堆栈
    (4)调度优先级
    (5)信号掩码(signal mask)
    (6) errno值
    (7)线程自定义数据

3:线程ID
   线程ID用pthread_t来表示,其类型在不同的系统中可能不同,有可能为一个整形,也可能为一个结构体。
   常用函数有如下两个:

  1. #include <pthread.h>
  2. int pthread_equal(pthread_t tid1, pthread_t tid2);
  3.              // 比较两个线程id是否相同,相同就返回非0,否则返回0

  4. pthread_t pthread_self(void);
  5.              // 返回线程的id

4:线程创建

  1. #include <pthread.h>

  2. int pthread_create(pthread_t *tidp, const pthread_attr_t *attr, void *(*start_rtn)(void *), void *arg);
调用pthread_create创建一个线程,函数返回后,tidp指针所指向地方保存了线程ID, 第二个参数为创建线程的属性,可直接用NULL,这样会使用默认属性。
第三个参数为线程要执行的函数,第四个参数为该函数的参数。

调用pthread_create后,线程会自动开始执行start_rtn函数。

5:线程的终止及返回值
如果在一个线程中调用了exit, _Exit, _exit那么整个进程都会终止。
终止线程有三种方法:
(1)在线程函数中调用return语句
(2)被其他线程使用pthread_cancel函数进行终止
(3)调用pthread_exit自行终止。

线程终止时,return或者pthread_exit调用时,指定了线程函数的返回值,那该返回值可通过pthread_join()函数来获取。

  1. #include<pthread.h>

  2. void pthread_exit(void *rval_ptr);

  3. int pthread_join(pthread_t tid, void **rval_ptr);
  4. int pthread_cancel(pthread_t tid);
  5. void pthread_cleanup_push(void (*rtn)(void *), void *arg);
  6. void pthread_cleanup_pop(int execute);
因为线程函数的返回值为一个指针,因此pthread_join函数的第二个参数需要传入指针的指针来获得线程的返回值。
如果线程是因为pthread_cancel导致的终止,那么pthread_join获得的返回值为PTHREAD_CANCELED。

pthread_cleanup_push函数的作用是注册相应的cleanup函数,在线程退出之前或执行这些函数,类似于进程中的atexit
三种情况会调用这些cleanup函数
(1)pthread_exit调用后
(2)响应pthread_cancel函数
(3)pthread_cleanup_pop函数调用,且参数为非0值。
pthread_cleanup_pop的传入参数为0的时候,会取消上一个注册的cleanup函数。

可以看出线程使用return语句返回和使用pthread_exit返回的区别,使用return返回不会调用cleanup函数。

注意pthread_cleanup_push和pthread_cleanup_pop函数必须成对调用。

6:线程的状态
线程处于运行或退出状态中。意思是说,当一个线程执行完成后,系统会保留其返回值还有其他部分资源,这样在调用pthread_join的时候能获取其返回值。
在调用pthread_join之后,线程处于detached状态,这时线程才算完全退出,其相关资源也被收回。
可以让一个线程在创建时设定其detached属性,于是线程执行完后,系统自动回收其资源,这时调用pthread_join无法获得其返回值。
后面讲述如何改变线程的这个属性。

7:线程同步
由于多个线程之间可能会访问同样的资源,因此为保证一致性,需要进行同步。
使用到的同步工具就是互斥锁、读写锁、条件变量

8:互斥锁

点击(此处)折叠或打开

  1. #include <pthread.h>

  2. PTHREAD_MUTEX_INITIALIZER

  3. int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);

  4. int pthread_mutex_destroy(pthread_mutex_t *mutex);

  5. int pthread_mutex_lock(pthread_mutex_t *mutex);
  6. int pthread_mutex_trylock(pthread_mutex_t *mutex);

  7. int pthread_mutex_unlock(pthread_mutex_t *mutex);

  8. int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int pshared);
  9. int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);

  10. PTHREAD_MUTEX_NORMAL
  11. PTHREAD_MUTEX_ERRORCHECK
  12. PTHREAD_MUTEX_RECURSIVE
  13. PTHREAD_MUTEX_DEFAULT

  14. int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);
  15. int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);
相关的函数包含初始化与销毁互斥锁:pthread_mutex_init,pthread_mutex_destroy
使用互斥锁:pthread_mutex_lock,pthread_mutex_trylock,pthread_mutex_unlock。 trylock表示仅尝试获得锁,若无法获得,则直接返回。
互斥锁的属性设置与获取:包含两个属性process-shared属性和type
process-shared属性表示该互斥锁是否可以在多个进程中使用,其值可为PTHREAD_PROCESS_SHARED或者PTHREAD_PROCESS_PRIVATE。
type属性表示互斥锁类型。默认为PTHREAD_MUTEX_NORMAL。区别如下:

type                                              relock without unlock        unlock when not owned             unlock when unlocked
PTHREAD_MUTEX_NORMAL                    死锁                                  未定义                                       未定义
PTHREAD_MUTEX_ERRORCHECK             返回错误                            返回错误                                    返回错误
PTHREAD_MUTEX_RECURSIVE                允许                                  返回错误                                    返回错误

但一个线程连续的lock一个互斥锁时,默认是出现死锁,如果要允许,必须设定属性为PTHREAD_MUTEX_RECURSIVE。
PTHREAD_MUTEX_RECURSIVE该属性主要用在将一个单线程的接口变成支持多线程的情况。
如果函数A调用了fun1和fun2,fun1和fun2都需要操作同一个全局变量。为了能多线程的调用函数A,需要在使用全局变量之前加锁。
如果fun1调用了fun2,如果使用默认的PTHREAD_MUTEX_NORMAL,则在fun1调用fun2之前需要unlock锁,但这是若有其他的线程调用了函数A,则
会出现问题,因此必须使用PTHREAD_MUTEX_RECURSIVE这样才能不需要unlock,继续在fun2中调用lock

fun1:                                                        fun2:
pthread_mutex_lock(mutex);                         pthread_mutex_lock(mutex);
// 访问全局变量                                            // 访问全局变量
....                                                             pthread_mutex_unlock(mutex);
//调用fun2
fun2()
.....
pthread_mutex_unlock(mutex);

9:读写锁
读写锁,该锁有3中状态:读模式、写模式、unlock。
在读模式下,其他的线程仍然可进入读模式,但要进入写模式必须等待
在写模式下,其他线程无法进行读模式或者写模式。

  1. #include <pthread.h>
  2. int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);

  3. int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

  4. int pthread_rwlock_rdlock(pthread_rwlock_t* rwlock);           // 请求进入读模式
  5. int pthread_rwlock_wrlock(pthread_rwlock_t* rwlock);           // 请求进入写模式
  6. int pthread_rwlock_unlock(pthread_rwlock_t* rwlock);           // unlcok

  7. int pthread_rwlock_tryrdlock(pthread_rwlock_t* rwlock);
  8. int pthread_rwlock_trywrlock(pthread_rwlock_t* rwlock);






待续................


 
































阅读(2103) | 评论(0) | 转发(0) |
0

上一篇:linux0.11 块设备驱动与高速缓冲区

下一篇:没有了

给主人留下些什么吧!~~