现在的位置: 首页 > 综合 > 正文

APUE Chapter 11笔记:UNIX下的线程(II)

2014年02月15日 ⁄ 综合 ⁄ 共 2431字 ⁄ 字号 评论关闭
/*随意转载,请注明原作者和出处。我想要找个工作,吃饭第一……*/

先推荐宫村优子的It's only fairy tales,连带推荐舞-HiME,就算不看动画内容,看MM也很happy。巨喜欢舞衣MM。然后推荐AIRANNE的Komm, süsser Tod,用最欢快的歌声唱出最忧郁的内容。

上次写到线程的共享同步方面的问题。线程的同步解决方法就是锁,这点用膝盖都能想出来。然而Unix并不支持数据的access锁。换句话说,这个锁就跟C++的public/protected/private机制一样,只是让愿意遵守条例的程序员遵守的条例。

第一种锁是Mutex锁。不知道中文翻译是什么,读的是英文版的书。应该可以称为一种粗粒度的锁。大约就是访问共享资源的时候锁上,访问结束就释放。对这把锁用之前要初始化,用过以后要销毁:
int pthread_mutex_init(pthread_mutex_t *restrict,const pthread_mutexattr_t *restrict);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
对锁的pthread_mutexattr_t以后讨论。注意C语言没有引用,要用指针解决问题。
上锁和去锁:
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
注意,前一个lock是线程会等待,直到获得锁为止。而对后一个lock,函数不会等待锁,得不到锁的话它会返回EBUSY。
窃以为对C++程序员,比较好的使用方法是把数据封装在类中,然后提供类的接口进行锁死和解锁。然而这样貌似就无须一个系统级的又没有真正锁定能力的工具。因为这个锁只是让愿意锁住数据的线程锁住数据的工具。一个线程完全可以无视这个mutex锁来访问数据,只要在访问数据前不申请锁定就可以了。

用这样的锁可能会引发死锁情况。一般程序员都不会愚蠢到试图两次锁定同一个锁,但是有可能两个线程分别锁定了一个资源,然而又开始等待对方锁定资源的锁。这是难以避免的痛苦。貌似Boost::Thread试图解决这个问题,暂且按下不提。APUE教育我们要小心。因为线程非常难调试,并且错误还很难重现。APUE提供的方案是尽量使用trylock并且及时释放锁,不要占着茅坑不拉屎。

Mutex锁似乎非常容易实现,应该是用宏来完成的。

第二类锁是读写锁,较Mutex锁粒度细。
int pthread_rwlock_init(pthread_rwlock_t *restrict, const pthread_rwlockattr_t *restrict);
int pthread_rwlock_destroy(pthread_rwlock_t *);
仍然是用前初始化,用后释放。
int pthread_rwlock_rdlock(pthread_rwlock_t *);
int pthread_rwlock_wrlock(pthread_rwlock_t *);
int pthread_rwlock_unlock(pthread_rwlock_t *);
分读锁,写锁和释放三种操作。APUE提到要注意rdlock读锁的返回值,因为可能读锁的使用次数会被限定,难道和Gease一样吗?!
int pthread_rwlock_tryrdlock(pthread_rwlock_t*);
int pthread_rwlock_trywrlock(pthread_rwlock_t*);
尝试上锁的工具。POSIX本身不支持,是Single UNIX协议的。

最后介绍的是条件变量(condition variable)。条件变量就像一个信号灯。程序可以等待之。初始化和析构:
int pthread_cond_init(pthread_cond_t *restrict,pthread_condattr_t *restrict);
int pthread_cond_destroy(pthread_cond_t *);
这个condition variable是由一个mutex守护的变量。一旦要改编状态,就必须先获得守护mutex的锁。

对于等待condition,有两个函数。根据APUE,等待的时候要上mutex的锁。
int pthread_cond_wait(pthread_cond_t *restrict,pthread_mutex_t *restrict);
int pthread_cond_timedwait(pthread_cond_t*restrict,pthread_mutex_t*restrict,const struct timespec
 *restrict);
后者中用到的timespec原型如下:
struct timespec {
            time_t tv_sec;   /* seconds */
            long   tv_nsec;  /* nanoseconds */
    };
用到的是绝对时间,也就是gettimeofday的时间。不过我质疑会不会有午夜0时现象的发生。

迄今为止,没有介绍condition是什么。之后APUE就暗示我们,这个条件变量就是一个红绿灯。因为等待的只有“唤醒”的信号:
int pthread_cond_signal(pthread_cond_t *);
int pthread_cond_broadcast(pthread_cond_t *);
没有pthread_cond_t具体能干什么的说明,可见就是一个红绿灯。前者唤醒第一个等待的线程,后者唤醒所有等待的线程。

Chapter 11完结。幻想到风华学园泡HiME MM们,看HiME去了。

抱歉!评论已关闭.