by pascal4123
并发多线程之间必须协调好彼此的动作,避免一个线程的操作错误地影响其他线程而导致发生各种古怪问题.
这就是同步的起因.
原子指令
同步要求必须具有一种原子操作指令.可以排它性地执行测试和设置.
所有的同步操作都是基于这样一种原子指令的存在.
Critical Sections 临界区必须保持数据完整性(原子性)的一段代码所有的共享数据都必须加锁保护.否则会导致古怪的问题.
具体地,这些共享数据包括:全局变量,static变量,传给其他线程的数据,被多线程共享的数据结构等.
同步变量
POSIX实现了3种同步变量.
有2件事你想做:
1.你想保护共享数据,这个通过锁实现.
2.你想阻止线程空转浪费时间.这通过信号量,条件变量,join等做到
mutex 互斥锁最简单.为代码段指定唯一的主人
.第一个加锁的线程获得互斥锁的所有权,后续的线程试图加锁都会失败,并进入睡眠状态.当第一个线程解锁时,睡眠者之一将有机会获得锁,转为可运行状态Runnablepthread_mutex_lock(m)
pthread_mutex_unlock(m)
互斥锁语句需要成对使用,
有可能临界段发生异常导致无法正常解锁!构建异常安全的互斥锁的办法之一是将锁功能注入一个类,利用类的析构函数自动解锁.具体实现参见另外一篇文章: http://blog.chinaunix.net/u/16651/showart.php?id=248476
个别情况下,你想避免得锁不成进入睡眠的情况,可以使用pthread_mutex_trylock(),得锁成功返回0,否则返回EBUSY. 这个函数很少用到,用的话要谨慎.
semaphores 信号量信号量对于串式的对象有用的.对于你想让线程等某件事情也是有用的.
信号量可以增加到任意大,但做多只能减小到零.信号量>0则操作成功.
P操作:sem_wait()
V操作:sem_post()
conditional variables 条件变量条件变量提供了一种安全环境让线程测试条件.
线程获得锁后,测试条件:如果真,就执行,否则就释放锁并返回睡眠状态.直到另外1个线程改变了条件并唤醒它.然后你的线程重新获得锁,重新测试条件.首先,别的线程唤醒你的线程之前可能没有完整地测试条件;
其次,就算唤醒之前条件真,等你被唤醒的线程准备开跑时条件可能变了;
第三,条件变量允许伪造的唤醒.
pthread_cond_signal() 唤醒某个睡眠的线程
pthread_cond_broadcast() 唤醒所有睡眠的线程
条件变量也允许你限制睡眠时间,到了一定时间就自动醒来
pthread_cond_timedwait()
可停止的生产者/消费者例子void *producer(void *arg)
{
request_t *request;
while(1)
{
request = get_request();
pthread_mutex_lock(&requests_lock);
while ((length >= 10) && (!stop))
pthread_cond_wait(&requests_producer, &requests_lock);
add_request(request);
length++;
if (stop) break;
pthread_mutex_unlock(&requests_lock);
pthread_cond_signal(&requests_consumer);
}
pthread_mutex_unlock(&requests_lock);
sem_post(&barrier);
pthread_exit(NULL);
}
void *consumer(void *arg)
{
request_t *request;
while(1)
{
pthread_mutex_lock(&requests_lock);
while ((length == 0) && (!stop))
pthread_cond_wait(&requests_consumer, &requests_lock);
if (stop) break;
request = remove_request();
length--;
pthread_mutex_unlock(&requests_lock);
pthread_cond_signal(&requests_producer);
process_request(request);
}
pthread_mutex_unlock(&requests_lock);
sem_post(&barrier);
pthread_exit(NULL);
}
void *stopper(void *arg)
{
sleep(4);
pthread_mutex_lock(&requests_lock); /* REQUIRED! */
stop = TRUE;
pthread_mutex_unlock(&requests_lock);
pthread_cond_broadcast(&requests_producer);
pthread_cond_broadcast(&requests_consumer);
pthread_exit(NULL);
}
阅读(1502) | 评论(0) | 转发(0) |