Solaris2.4 多线程编程指南3--使用同步对象编程
失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
3.4.4关于一个信号量阻塞
sema_wait(3T)
#include(or #include )
int sema_wait(sema_t *sp)
用sema_wait()使得调用线程在由sp指向的信号量小于等于零时阻塞,在其大于零原子地对其进行减操作。
返回值--sema_wait()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
EINTR 等待被信号或fork()打断。
3.4.5给信号量减值
sema_trywait(3T)
#include(or #include )
int sema_trywait(sema_t *sp)
用sema_trywait()在sp比零大时对它进行原子地减操作。是sema_wait()的非阻塞版本。
返回值--sema_trywait()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
EBUSY sp 指向的值为零。
3.4.6清除信号量的状态
sema_destroy(3T)
#include(or #include )
int sema_destroy(sema_t *sp)
用sema_destroy(3T)破坏与sp指向的信号量关联的任何状态,但空间不被释放。
返回值--sema_destroy()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
3.4.7用信号量解决生产者/消费者问题
示例3-15所示的程序与条件变量的解决方案类似;两个信号量代表空和满的缓冲区的数目,生产者线程在没有空缓冲区时阻塞,消费者在缓冲区全空时阻塞。
Code Example 3-15 用信号量解决的生产者/消费者问题
Typedef struct{
Char buf[BSIZE];
Sema_t occupied;
Sema_t empty;
Int nextin;
Int nextout;
Sema_t pmut;
Sema_t cmut;
} buffer_t;
buffer_t buffer;
sema_init(&buffer.occupied, 0, USYNC_THREAD, 0);
sema_init(&buffer.empty, BSIZE, USYNC_THREAD, 0);
sema_init(&buffer.pmut, 1, USYNC_THREAD, 0);
sema_init(&buffer.cmut, 1, USYNC_THREAD, 0);
buffer.nextin=buffer.nextout =0;
另外一对信号量与互斥锁作用相同,用来在有多生产者和多个空缓冲区的情况下,或者是有多个消费者和多个满的缓冲区的情况下控制对缓冲区的访问。互斥锁同样可以工作,但这里主要是演示信号量的例子。
Code Example 3-16 生产者/消费者问题--生产者
Void producer(buffer_t *b, char item){
Sema_wait(&b->empty);
Sema_wait(&b->pmut);
b->buf[b->nextin]=item;
b->nextin++;
b->nextin %=BSIZE;
sema_post( &b->pmut);
sema_post(&b->occupied);
}
Code Example 3-17 生产者/消费者问题--消费者
Char consumer(buffer_t *b){
Char item;
Sema_wait(&b->occupied);
Sema_wait(&b->cmut);
Item=b->buf[b->nextout];
b->nextout++;
b->nextout %=BSIZE;
sema_post (&b->cmut);
sema_post(&b->empty):
return(item);
}
3.5进程间同步
四种同步原语中的任何一种都能做进程间的同步。只要保证同步变量在共享内存 段,并且带USYNC_PROCESS参数来对其进行初始化。在这之后,对同步变量的使用和 USYNC_THREAD初始化后的线程同步是一样的。
Mutex_init(&m, USYNC_PROCESS,0);
Rwlock_init(&rw, USYNC_PROCESS,0);
Cond_init(&cv,USYNC_PROCESS,0);
Sema_init(&s,count,USYNC_PROCESS,0);
示例3-18显示了一个生产者/消费者问题,生产者和消费者在两个不同的进程里。 主函数把全零的内存段映射到它的地址空间里。注意mutex_init()和cond_init()一 定要用type=USYNC_PROCESS来初始化。
子进程运行消费者,父进程运行生产者。
此例也显示了生产者和消费者的驱动程序。生产者驱动producer_driver()简单 地从stdin中读字符并且调用生产者函数producer()。消费者驱动consumer_driver() 通过调用consumer()来读取字符,并将其写入stdout。
Code Example 3-18 生产者/消费者问题,用USYNC_PROCESS
Main(){
Int zfd;
Buffer_t * buffer;
Zfd=open("/dev/zero", O_RDWR);
Buffer=(buffer_t *)mmap(NULL, sizeof(buffer_t),
PROT_READ|PROT_WRITE, MAP_SHARED, zfd, 0);
Buffer->occupied=buffer->nextin=buffer->nextout=0;
Mutex_init(&buffer->lock, USYNC_PROCESS,0);
Cond_init(&buffer->less, USYNC_PROCESS, 0);
Cond_init(&buffer->more, USYNC_PROCESS, 0);
If(fork()==0)
Consumer_driver(buffer);
Else
Producer_driver(buffer);
}
void producer_driver(buffer_t *b){
int item;
while(1){
item=getchar();
if(item==EOF){
producer(b, '');
break;
} else
producer(b, (char)item);
}
}
void consumer_driver(buffer_t *b){
char item;
while (1) {
if ((item=consumer(b))=='')
break;
putchar(item);
}
}
一个子进程被创建出来运行消费者;父进程运行生产者。
3.6同步原语的比较
Solaris中最基本的同步原语是互斥锁。所以,在内存使用和执行时它是最 有效的。对互斥锁最基本的使用是对资源的依次访问。
在Solaris中效率排第二的是条件变量。条件变量的基本用法是关于一个状态 的改变而阻塞。在关于一个条件变量阻塞之前一定要先获得互斥锁,在从 cond_wait()返回且改变变量状态后一定要释放该互斥锁。
信号量比条件变量占用更多的内存。因为信号量是作用于状态,而不是控制 ???,所以在一些特定的条件下它更容易使用。和锁不同,信号量没有一个所 有者。任何线程都可以给已阻塞的信号量增值。
读写锁是Solaris里最复杂的同步机制。这意味着它不象其他原语那样细致 ???。一个读写锁通常用在读操作比写操作频繁的时候。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
3.4.4关于一个信号量阻塞
sema_wait(3T)
#include
int sema_wait(sema_t *sp)
用sema_wait()使得调用线程在由sp指向的信号量小于等于零时阻塞,在其大于零原子地对其进行减操作。
返回值--sema_wait()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
EINTR 等待被信号或fork()打断。
3.4.5给信号量减值
sema_trywait(3T)
#include
int sema_trywait(sema_t *sp)
用sema_trywait()在sp比零大时对它进行原子地减操作。是sema_wait()的非阻塞版本。
返回值--sema_trywait()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
EBUSY sp 指向的值为零。
3.4.6清除信号量的状态
sema_destroy(3T)
#include
int sema_destroy(sema_t *sp)
用sema_destroy(3T)破坏与sp指向的信号量关联的任何状态,但空间不被释放。
返回值--sema_destroy()在成功执行后返回零。其他值意味着错误。在以下情况发生时,函数失败并返回相关值。
EINVAL 非法参数。
EFAULT sp指向一个非法地址。
3.4.7用信号量解决生产者/消费者问题
示例3-15所示的程序与条件变量的解决方案类似;两个信号量代表空和满的缓冲区的数目,生产者线程在没有空缓冲区时阻塞,消费者在缓冲区全空时阻塞。
Code Example 3-15 用信号量解决的生产者/消费者问题
Typedef struct{
Char buf[BSIZE];
Sema_t occupied;
Sema_t empty;
Int nextin;
Int nextout;
Sema_t pmut;
Sema_t cmut;
} buffer_t;
buffer_t buffer;
sema_init(&buffer.occupied, 0, USYNC_THREAD, 0);
sema_init(&buffer.empty, BSIZE, USYNC_THREAD, 0);
sema_init(&buffer.pmut, 1, USYNC_THREAD, 0);
sema_init(&buffer.cmut, 1, USYNC_THREAD, 0);
buffer.nextin=buffer.nextout =0;
另外一对信号量与互斥锁作用相同,用来在有多生产者和多个空缓冲区的情况下,或者是有多个消费者和多个满的缓冲区的情况下控制对缓冲区的访问。互斥锁同样可以工作,但这里主要是演示信号量的例子。
Code Example 3-16 生产者/消费者问题--生产者
Void producer(buffer_t *b, char item){
Sema_wait(&b->empty);
Sema_wait(&b->pmut);
b->buf[b->nextin]=item;
b->nextin++;
b->nextin %=BSIZE;
sema_post( &b->pmut);
sema_post(&b->occupied);
}
Code Example 3-17 生产者/消费者问题--消费者
Char consumer(buffer_t *b){
Char item;
Sema_wait(&b->occupied);
Sema_wait(&b->cmut);
Item=b->buf[b->nextout];
b->nextout++;
b->nextout %=BSIZE;
sema_post (&b->cmut);
sema_post(&b->empty):
return(item);
}
3.5进程间同步
四种同步原语中的任何一种都能做进程间的同步。只要保证同步变量在共享内存 段,并且带USYNC_PROCESS参数来对其进行初始化。在这之后,对同步变量的使用和 USYNC_THREAD初始化后的线程同步是一样的。
Mutex_init(&m, USYNC_PROCESS,0);
Rwlock_init(&rw, USYNC_PROCESS,0);
Cond_init(&cv,USYNC_PROCESS,0);
Sema_init(&s,count,USYNC_PROCESS,0);
示例3-18显示了一个生产者/消费者问题,生产者和消费者在两个不同的进程里。 主函数把全零的内存段映射到它的地址空间里。注意mutex_init()和cond_init()一 定要用type=USYNC_PROCESS来初始化。
子进程运行消费者,父进程运行生产者。
此例也显示了生产者和消费者的驱动程序。生产者驱动producer_driver()简单 地从stdin中读字符并且调用生产者函数producer()。消费者驱动consumer_driver() 通过调用consumer()来读取字符,并将其写入stdout。
Code Example 3-18 生产者/消费者问题,用USYNC_PROCESS
Main(){
Int zfd;
Buffer_t * buffer;
Zfd=open("/dev/zero", O_RDWR);
Buffer=(buffer_t *)mmap(NULL, sizeof(buffer_t),
PROT_READ|PROT_WRITE, MAP_SHARED, zfd, 0);
Buffer->occupied=buffer->nextin=buffer->nextout=0;
Mutex_init(&buffer->lock, USYNC_PROCESS,0);
Cond_init(&buffer->less, USYNC_PROCESS, 0);
Cond_init(&buffer->more, USYNC_PROCESS, 0);
If(fork()==0)
Consumer_driver(buffer);
Else
Producer_driver(buffer);
}
void producer_driver(buffer_t *b){
int item;
while(1){
item=getchar();
if(item==EOF){
producer(b, '');
break;
} else
producer(b, (char)item);
}
}
void consumer_driver(buffer_t *b){
char item;
while (1) {
if ((item=consumer(b))=='')
break;
putchar(item);
}
}
一个子进程被创建出来运行消费者;父进程运行生产者。
3.6同步原语的比较
Solaris中最基本的同步原语是互斥锁。所以,在内存使用和执行时它是最 有效的。对互斥锁最基本的使用是对资源的依次访问。
在Solaris中效率排第二的是条件变量。条件变量的基本用法是关于一个状态 的改变而阻塞。在关于一个条件变量阻塞之前一定要先获得互斥锁,在从 cond_wait()返回且改变变量状态后一定要释放该互斥锁。
信号量比条件变量占用更多的内存。因为信号量是作用于状态,而不是控制 ???,所以在一些特定的条件下它更容易使用。和锁不同,信号量没有一个所 有者。任何线程都可以给已阻塞的信号量增值。
读写锁是Solaris里最复杂的同步机制。这意味着它不象其他原语那样细致 ???。一个读写锁通常用在读操作比写操作频繁的时候。

