martin

thinking

常用链接

统计

software

最新评论

unix 类系统中的进程同步方式代码示例

MP(多CPU)同步原语代码示例
                   ----引自《现代体系结构上的UNIX系统》

为了便于对示例的展开,我们首先假定一个场景:
内核中把检测到的错误信息记录到一个磁盘文件中的情形。出错信息通过内存中的一个队列来传递给日志进程(logging process)的。
当出现一个错误时,就在队列中加入一项,并且通过调用函数log_error 通知日志进程。出错日志进程接着把队列中的项写到磁盘上。
这就使得碰到错误的进程不必等候I/O完成或者或得为了向文件执行I/O而可能需要的任何锁,并且避免了任何可能的上锁次序问题。

代码1, 采用事件计数的出错日志通知机制

                                                日志进程
log_error(error)                    |
{                                         |       for(next=1; ; next++) {
    lock(&err_queue);             |           await(&err_event, next);
    把出错信息加入到队列           |          lock(&err_queue);
    unlock(&err_queue);          |          从队列中删除项
    advance(&err_event);        |          unlock(&err_queue);
}                                         |          write error to disk
                                           |       }

队列本身由一个自旋锁来保护。在本例中,事件计数只用于同步的目的,并不提供互斥。
在试用事件计数的时候,advance操作会永久性地改变事件计数的状态。advance和await操作的相对时序没有关系。

代码2, 采用同步变量的出错日志通知机制
                                                 日志进程
log_error(error)                            |
{                                                 |        for(;;){
   lock(&err_queue);                      |              lock(&err_queue);
   把出错信息加入到队列                    |              if (queue_empty){
   SV_SIGNAL(&err_syncvar, 0);      |                  SV_WAIT(&err_syncvar, PRI, &err_queue);
   unlock(&err_queue);                   |                  lock(&err_queue);
}                                                 |              }
                                                   |              从队列中删除项
                                                   |              unlock(&err_queue);
                                                   |              把错误写入磁盘
                                                   |        }

因为同步变量自身没有保留状态,所以当日志进程测试队列的状态并决定是等待一项还是从队列中删除一项的时候,必须占有自旋锁。类似地,log_error在
发送信号时也必须占有自旋锁。注,SV_WAIT将释放自旋锁,并且阻塞日志进程,SV_SIGNAL到后从阻塞处继续执行。

代码3, 采用管程的出错日志通知机制
                                                                 日志进程
log_error(error)                                  |       for(;;){
{                                                       |           mon_enter(&err_mon);
   mon_enter(&err_mon);                     |           if (queue empty)
   把出错信息加入到队列                          |               mon_wait(&err_mon, NEWENTRY);
                                                         |
   mon_signal(&err_mon, NEWENTRY);  |           从队列中删除项
   mon_exit(&err_mon);                       |           mon_exit(&err_mon);
}                                                       |           把错误写入磁盘
                                                         |       }
                                    
代码4, 采用信号量的出错日志通知机制
                                                日志进程
log_error(error)                      |       for(;;){
{                                          |           P(&err_sema);
    lock(&err_queue);               |           lock(&err_queue);
    把出错信息加入到队列            |           从队列中删除项
    unlock(err_queue);              |           unlock(&err_queue);
    V(&err_sema);                   |           把错误写入磁盘
}                                          |       }

posted on 2013-06-20 15:02 martin_yahoo 阅读(1354) 评论(0)  编辑 收藏 引用


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理