存档:2008年十二月

别了,我们的2008(2)

十二月 31, 2008 | 心情杂记 | RSS 2.0

望了望下电脑下边,发现2008真的只剩下几分钟了,几多留恋,几多不舍,发生了几件大雷,大地震,奥运会,雪灾,等等,每件事都是惊世骇俗,百载难逢,所以说2008真的很珍贵,也许多年后会让我们频频的回忆这一年,这一年我也很雷,将要20年的学生生涯终于画上了一个句号,虽然不够完美,那也是那么的潇洒,纵有许多遗憾,那也是小有成果。2008也是我的一生难以忘却,弥足珍贵的一年。踏入了社会,认识了好多高人,从他们哪里学到了好多治学,思考问题的方法,更多的是从书上,别人的博客上学到了很多知识,弥补了好多知识的欠缺,遗憾自己以前的无知,但我相信我一定要补习上。总之以后的目标就是这样,要勤于修身,多扩充下知识面,修养,听听古典名曲,看看一些名人自传,学习下别人的治学修身的例子,例如曾国藩就是个典型,老毛曰:吾于近人,独服曾文正,蒋介石也是终其一生在研究他,足见你影响力,另外是要学会严谨专注的治学态度,把自己的老本行学好,要学精,多看看别人的博客是如何解决问题,分析问题的。再一个就是锻炼自己的身体,把身体养好,还有积极的做点创业的准备,无论从知识上,还是技术上来说。学会批判性思考问题。就是这样。这个三点就是这样,也是我的2009年的基本目标。
勤于修身,严谨专注的治学,锻炼身体。似乎只有这样三件事
再见2008,2009充满希望,充满期待,希望我的2009更加顺利,更加丰富多彩。

没有评论 »

PHP Iterator Standard PHP Library (SPL) Functions

十二月 31, 2008 | php, 软件工程/编程技巧/设计模式 | RSS 2.0

PHP 迭代器 (转)

感谢,bitbird对我的指导 


PHP 迭代器

作者: Dejan Bosanac
译者: detrox

PHP arrays are generally a very powerful objectcontainer. But still, we can easily add a little more fuel to them.Imagine an iterator object as a kind of wrapper around our arrays. Whatwe will try to accomplish here is to create unique interface fortraversing arrays and to add a little more control over how our objectsare created and finally, to support lazy loading.

PHP数组一般地说是一个十分强大的对象容器。但我们仍然可以给他来点涡轮增压。把迭代器对象设想为一种数组的包装。我们要在这里试着完成的是为遍历数组和在如何创建对象上加入一点额外的控制去创建一个唯一的接口,最后去支持傻瓜式的读取。

Interface
接口

Iterator has a very simple and many times seen interface.

迭代器有一个简单的和经常被看到的接口

<?php
function Iterator($array) // Constructor. Takes array to be traversed as a parameter. 构造函数。使需要遍历的数组作为一个参数
function reset() // Sets internal pointer to the first element 设置内部指针指向第一个元素
function end() // Sets internal pointer to the last element 设置内部指针指向最后一个元素
function seek($position) // Sets internal pointer to desired position 设置内部指针指向一个指定的元素
function next() // Returns next element in the iteration 返回后一个元素
function previous() // Returns previous element in the iteration 返回前一个元素
?>

With the interface like this you can easily perfoRM allyour daily tasks (such as traversing arrays) in any way you want andfrom any position you want. One advantage of using this approachagainst native PHP array functions is that you have one interface forall of your array tasks. You will not use foreach() construct in onecase, list-each combination in other and yet next() and prev()functions in third any more. One more advantage is that now you caneasily position on any particular element and start traversing fromthere (in any way you want). Here are few code examples:

有了这样的接口,我们就可以在任何时间,任何地点,用我们喜欢的任何方法轻轻松松执行我们的日常事务(像数组遍历)。使用这个东西相对于PHP本身的数组函数的一个优势就是你有了一个为你的所有数组任务[工作]的接口。你就用不着在一段代码里用foreach()构造,另外一段用list和each的组合,然后还有别的地方一会儿用到next(),一会儿用到perv()。另一个优势是现在你可以简单的定位于一个确定的元素并且可以从这里开始遍历(以你想要得任何方式). 这里有一些例子:

<?php
// $array = ?. // initialize the array 初始化数组
$iterator = new Iterator($array);
// traverse the array 遍历数组
while ($elem = $iterator->next()) {
echo $elem;
}

// traverse array in reverse order 反序便利
$iterator->end();
while ($elem = $iterator->previous()) {
echo $elem;
}

// traverse array from fifth element on 从第五元素开始遍历
$iterator->seek(5);

while ($elem = $iterator->next()) {
echo $elem;
}
?>

OK, you say, this is all nice but there is nothing I can’t do with combination of native PHP functions. Besidesthe fact that you are accessing all your arrays through uniqueinterface, another (and most important) advantage is that Iterator’sobject structure allows you to easily expand its functionality.

OK, 你说,这是很不错,但是没有什么我不能使用原始的PHP函数组合来完成的。除了这个事实,你能通过唯一的接口存取你的所有数组,另外(也是最重要的)优势是迭代器的对象结构容许你轻松的扩展它的功能

ObjectIterator interface
对像迭代器器接口

Often I have ended up in situations where my object methods had toreturn an array of some other object as a result. Usually that objectis loaded from the database, but could be some other situation such asobtaining objects through some RPC protocol (XML-RPC, SOAP,…) or endless other situation combinations that you experience everyday. In this article we will focus on the first problem and brieflyexplain how to empower Iterator for the purpose you’d need.

我经常中断于我的对象方法要返回一些其他对象的数组作为结果[的情况]。通常这钟对象是从数据库读取得,但是也可能是其他状况比如获得一个通过一些RPC 协议 (XML-RPC, SOAP,…) 得到的对象或是你每天要经历的无尽的其他情况的组合。在这篇文章中,我们将聚焦在第一个问题并且简要的解释如何去为你的目的实现迭代器。

Suppose that you are developing an address book for some large webapplication. Your address book will work with companies and persons. Inaddition, companies could have an endless number of employees (that arealso kinds of persons). So far we have recognized two objects in ourapplication: Company and Person. Also, it is clear that the companywill have method getEmployees() that returns an array of Personobjects. There are a number of possible implementations of this method.Here are some usual implementations:

假设你在为一个大型web应用程序开发一个通讯录。你的通讯录将工作在公司和人上。另外,公司可能有无穷多的雇员(这也是一类人)。现在我们认清了应用程序中的两个对象:公司和个人。同时也清楚了Company将有一个方法getEmployees()返回一个人对象的数组。这个方法的实现有很多。这里是一些常规的实现方法:

First, you could write a query to collect all the ids of all thecompany employees. Then you could make an array that contains all theobjects and returns this array. This would look something like this(supposing you have a database

首先,你可以写一个查询去收集所有公司员工的id。然后,你能制造一个数组包含所有的对象再返回这个数组。这看上去像这样(假设你有一个数据库)

<?php
function getEmployees() {
$query = “select id FROM persons WHERE companyid = $this->companyid”;
$stmt = execute_query($query); // creates statement object 创建语句对象
$this->employees = array();

while ($row = fetch_object($stmt) {
$this->employess[$row->id] = new Person($row->id); // object creation 对象创建
}

return $this->employees;
}
?>

and the usage would be:

使用起来像是这样:

<?php
$company = new Company(”Datagate”);
$employees = $company->getEmployees();
foreach ($employees as $id =>$employee)
$employee->addVacationDays(3); // object usage 对象的使用
?>

OK, these look like fairly obvious solutions. But, it has few bigflaws. All objects are created but we don’t know if we’re going to usethem all. There are two performance problems here. First accessing arelational database (for creating these objects) can be very timeexpensive. And if the company has 500 employees and you need to accessdata for only 50, that is lot of time wasted. Imagine now, that we areloading these objects through RPC which is even slower. This couldseriously affect application performance. Now, even if all objects areneeded we don’t need them at the same time, we need objects one by oneas we are traversing the array. The solution above is a huge waste of resources (memory and time).

OK, 这些看上去像是清晰明确的解决方案。但是,它存在一些大的瑕疵。所有的对象都被创建但我们却不知道他们是否都要被使用。这里有两个性能的问题。首先存取一个关系数据库(为了创建这些对象)时间开销很大。其次,如果公司有500个员工并且你只需要为其中50个存取数据,这将是极大的时间上的浪费。现在想象一下,我们将这些对象通过更缓慢的RPC读取。这将严重的影响应用程序的性能。现在,即使所有的对象都是被需要的我们也不是在同一时间需要他们,我们需要一个接着一个的[处理]对象就像我们在遍历一个数组。上面的解方案是一个巨大的资源(内存和时间)浪费。

The solution to these performance problems looks so obvious. Let’sreturn just an array of employee ids. The code would look somethinglike this:

对于这个性能问题的解决方案看起来是那么显而易见。让我们来仅仅返回一个包含员工id的数组。代码看上去像是这样的:

<?php
function getEmployees() {
$query = “SELECT id FROM persons WHERE companyid = $this->companyid”;
$stmt = execute_query($query); // creates statement object
$this->employees = array();
while ($row = fetch_object($stmt) {
$this->employess[$row->id] = $row->id;
}
return $this->employees;
}
?>

and the usage would be:

使用就是这样:

<?php
$company = new Company(”Datagate”);
$employees = $company->getEmployees();
foreach ($employees as $id) {
$employee = new Employee($id); // object creation
$employee->addVacationDays(3); // object usage
}
?>

This looks fine at the first sight. We have saved time and memory ,but another problem has arisen. Suppose that the code for creatingEmployee object changes, for example you need to add extra argument tothe constructor or some extra initialization (these are things that arehappening on real projects). In that case you’ll need to modify yourcode in many places (wherever you have used getEmployees() method), Andthat is a problem.

第一眼看上去挺不错。我们节省了时间和内存,但是另一个问题出现了。假设为创建员工对象的代码发生了变化,例如你需要给构造函数加入额外的参数或者一些额外的初始化(这是真实的项目中将会发生的)。在这个问题上,你将要在很多地方修改你的代码(任何你使用getEmployees()方法的地方),这是个问题。

The third solution is to use an ObjectIterator class that isextended from Iterator. In this example we will see how easy it is toextend Iterator class to serve your purposes. When you are usingObjectIterator your getEmployee() function will stay the same as insecond solution. So, we have saved our resources. No unnecessaryobjects are created and everything looks just fine. Now let’s look atthe usage code:

第三个解决方案是使用一个对象迭代器类,它迭代器的扩展。在这个例子里我们将看到扩展迭代器为你的目的服务是何等容易。当你在使用对象迭代器时你的getEmployee()[应该是getEmplyees()吧]函数将保持和第二个解决方案一样。因此,我们节省了我们的资源。没有不需要的对象被创建而且每件事看上去都很好。现在,让我们看看使用代码:

<?php
$company = new Company(”Datagate”);
$iterator = new Iterator($company->getEmployees(), “Employee”);
while ($employee = $iterator->next()) {
$employee->addVacationDays(3);
}
?>

We see now that the object creation code is hidden in the ObjectIterator class, so it is now easy to support changes.

我们现在看到了对象创建的代码被隐藏在对象迭代器类里,因此现在很容易去支持改变。

ObjectIterator implementation
对象迭代器的实现

The code for ObjectIterator is quite simple.
对象迭代器的代码十分简单

<?php
/**
* Implements iterator for traversing collection of objects
* for the given array od object identifiers
*
* @version 1.0
* @author <a href=Mailto:chubrilo@yahoo.com>Dejan Bosanac</a>
*/
class ObjectIterator extends Iterator { var $_objectName;
/**
* Constructor
* Calls initialization method (@see Iterator::_initialize())
* and do some specific configuration
* @param array $array array of object ids to be traversed
* @param string $objectName class of objects to be created
* @access public
*
* 构造函数
* 调用初始化方法(参考Iterator::_initialize())
* 做一些特殊的配置
* @参数数组 $array 要遍历的对象id的数组
* @参数字符串 $objectName 要被创建的对象的类
*/
function ObjectIterator($array, $objectName) {
$this->_initialize($array);
$this->_objectName = $objectName;
}
/**
* Returns object with given id
* @param Object $id identifier of the object
* @return Object next object in the collection
* @access private
*
* 用给出的id返回对象
* @参数对象 $id 标示一个对象
* @返回对象 集合里的下一个对象
* @存取 私有
*/
function _fetchObject($id) {
return new $this->_objectName($id);
}
}
?>

It has $_objectName class member that represent class of the objectthat has to be returned by next() and previous() methods. Theconstructor sets this internal variable and calls an initializationfunction (defined in Iterator class). The most important thing is the_fetchObject() function. It encapsulates code for object creation. Itis called from next() and previous() methods and takes object id as aparameter. So all your object creation code is localized here, thusmaking it easy to change and expand.

类成员$_objectName代表对象所属的类它必须被next()和pervious()方法返回。构造函数设置内部变量并且调用初始化函数(已经在迭代器类定义了)。最重要的事情是_fetchObject()函数。他封装了对象创建的代码。它被next()和pervious()方法调用并且用对象的id作为参数)。这样一来你所有的对象创建代码都在这里了,因此他被制作的容易改变和扩展

So, here are instructions for creating our new type of iterators.First, make your constructor (which has to have an array as aparameter) which calls _initialize() function from Iterator class.Second, override _fetchObject method to do whatever you have to do tomake your objects. And, that would be all.

这里是我们创建新的一类迭代器的方法。第一,制作你的构造函数(它有一个数组作为参数),它调用从迭代器类_initialize()函数。第二,重载 _fetchObject方法去做任何你必须对你的对象做的。这就是全部。

In conclusion
结论

Iterator will not slow down your application in a way that it willneed new hardware to run it. It has some overhead, but for that priceyou get clean and easy readable code that is flexible enough for futuresoftware enhancements.

迭代器不会以任何方式减慢你的应用程序除非它需要一套新的硬件去运行。它有一些负荷,但是给了你清晰易读的代码,这将使今后软件的扩展十分方便

.NET.yu/~chuki/DOWNLOAD/iterator.tar.gz”>你可以在这里下载源程序

没有评论 »

linux pipe 管道学习

十二月 31, 2008 | c/c++, linux | RSS 2.0

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>

/* Write COUNT copies of MESSAGE to STREAM, pausing for a second
   between each.  */

void writer (const char* message, int count, FILE* stream)
{
  for (; count > 0; –count) {
    /* Write the message to the stream, and send it off immediately.  */
    fprintf (stream, “%s”, message);
    fflush (stream);
    /* Snooze a while.  */
    sleep (1);
  }
}

/* Read random strings from the stream as long as possible.  */

void reader (FILE* stream)
{
  char buffer[1024];
  /* Read until we hit the end of the stream.  fgets reads until
     either a newline or the end-of-file.  */
  while (!feof (stream)
     && !ferror (stream)
     && fgets (buffer, sizeof (buffer), stream) != NULL)
    fputs (buffer, stdout);
}

int main ()
{
  int fds[2];
  pid_t pid;

  /* Create a pipe.  File descriptors for the two ends of the pipe are
     placed in fds.  */
  pipe (fds);
  /* Fork a child process.  */
  pid = fork ();
  if (pid == (pid_t) 0) {
    FILE* stream;
    /* This is the child process.  Close our copy of the write end of
       the file descriptor.  */
    close (fds[1]);
    /* Convert the read file descriptor to a FILE object, and read
       from it.  */
    stream = fdopen (fds[0], “r”);
    reader (stream);
    close (fds[0]);
  }
  else {
    /* This is the parent process.  */
    FILE* stream;
    /* Close our copy of the read end of the file descriptor.  */
    close (fds[0]);
    /* Convert the write file descriptor to a FILE object, and write
       to it.  */
    stream = fdopen (fds[1], “w”);
    writer (”Hello, world.”, 5, stream);
    close (fds[1]);
  }

  return 0;
}

没有评论 »

别了,我们的2008(1)

十二月 30, 2008 | 心情杂记 | RSS 2.0

时间又要在某一个阶段花而且上句号了,人生的旅程也在某个过程悄悄的滑过了,还记得上一年的这个时候,一个人独自来到北京,看到的都是一个个的陌生人,没有情,只有钱,想起来一个人花了30元钱在一个旅馆住了一个晚上,而且几个人在一块,在异地他乡,真的心里凉凉的,想起来了老家,想起来了学校的女朋友,朋友。。。。。。他们的残留的温存依然在心间,而那是的我刚刚逃出了学校的校门,除了新鲜刺激外都是孤独,还带着半分恐惧,自卑,那时候的2008对我充满了期望,像一朵含苞待放的花朵,期待自己能有好的征程,记得高考时候的不理想时候进了学校都发誓进了学校好好学习,2008到北京去看奥运会,岂不是上天给的机会,是的,在那时候看来我是拿到了到北京的入场券。2008也是我的出境下展开了他的画卷,让我尽情的挥洒,现在看来尽管我画的不是那么漂亮,但我感觉到了他的精彩,体会到了他的活力,摸清了他的动脉。
别了2008 ,人生的路程里唯有2008 最具有特殊的意义,自己,自己外的事物,都这样的异常。但还是要挥别。。。。。。。。

没有评论 »

second ipc mmap

十二月 30, 2008 | c/c++, linux | RSS 2.0

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#define FILE_LENGTH 0×100
/*return a uniformly random number in the range [low,high]*/
int random_range(unsigned const low,unsigned const high)
{
    unsigned const range =high-low+1;
    return low+(int)(((double)range)*rand()/(RAND_MAX+1.0));
}
int main(int argc,char* const argv[])
{
    int fd;
    void* file_memory;
    /*seed the random number generator*/
    /*prepare a file large enough to hold an unsigned integer*/
    fd = open(argv[1],O_RDWR|O_CREAT,S_IRUSR|S_IWUSR);
    lseek(fd,FILE_LENGTH+1,SEEK_SET);
    write(fd,”",1);
    lseek(fd,0,SEEK_SET);
    /*create the memory mapping*/
    file_memory = mmap(0,FILE_LENGTH,PROT_WRITE,MAP_SHARED,fd,0);
    close(fd);
    /*write a random integer to memory-mapped area*/
    sprintf((char*)file_memory,”%d”,random_range(-100,100));
    /*release the memory */
    munmap(file_memory,FILE_LENGTH);
    return 0;
}
read
#include<stdio.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/stat.h>
#include<unistd.h>
#define FILE_LENGTH 0×100
int main(int argc ,char* const argv[])
{
  int fd;
  void* file_memory;
  int integer;
  /*open the file*/
  fd = open(argv[1],O_RDWR,S_IRUSR|S_IWUSR);
  /*create the memory mapping*/
  file_memory = mmap(0,FILE_LENGTH,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
  close(fd);
  scanf(file_memory,”%d”,&integer);
  printf(”value:%d”,integer);
  sprintf((char*)file_memory,”%d”,2*integer);
  munmap(file_memory,FILE_LENGTH);
  return 0;

}

没有评论 »

信号灯

十二月 28, 2008 | c/c++, linux | RSS 2.0

互斥的概念
在Unix中经常遇到多个进程需要使用同一资源的情况。共享资源对每个进程而言就是一份完全属于自己的拷贝。但是由于资源是共享的,就会产生问题:在任意两次操作之间,如果其它进程对该资源做了更改,本进程是无法知道其状态的,因此也不可能进行有效的控制。如果对资源的两次操作是有因果关系的,则更不允许其它进程在操作期间改变资源状态。
因此必须提供互斥机制以使一次只能由一个进程使用资源。常用的方法有文件封锁、信号灯等。文件封锁和信号灯都能够用于Unix文件系统读写的互斥,但信号灯主要用于实现不同进程对共享内存的存取。信号灯作为进程间通信(IPC)的一种方式,不象管道、消息队列那样用于传递大量数据,而是提供了一种机制用来协调不同进程间的同步。
本文阐述了Unix System V下信号灯的使用方法,以及如何通过信号灯实现对共享内存的读写操作。
2信号灯的使用
2.1信号灯的概念
信号灯是一个整数变量,用来代表资源计数器,记录了某个时刻可以获得的资源的数目。最简单的情况是一个二值信号灯,它只有两个值:0和1,分别表示一个资源的“可用”和“不可用”状态。
System V下的信号灯是一个复杂的数据结构,它代表一个非负整数的集合,该集合元素的个数以及每个元素的取值范围都只受系统资源的限制。内核为系统的每个信号灯都维持如下数据结构(其定义包含在头文件sys/sem.h中):
struct semid_ds{
                struct ipc_perm sem_perm;        /* operation permission                        */
                struct sem                *sem_base;        /* ptr to first semaphore in set        */
                unsigned short        sem_nsems;        /* number of semaphores in set        */
                time_t                        sem_otime;        /* last semop time                                */
                time_t                        sem_ctime;        /* last change time                                */
};
ipc_perm结构记录了关于信号灯的所有者、同组者和其他用户的PID号,信号灯的读写权限,操作顺序以及信号灯的键值(KEY)等信息。该数据结构适用于所有使用全局唯一标识号KEY的进程通信。其定义参见sys/ipc.h。
sem结构指明了每一个信号灯的值和使用状态,其定义如下(包含在头文件sys/sem.h中):
struct sem{
        unsigned short semval;                /* semaphore value.                        */
        pid_t                   sempid;                /* pid of last operation.        */
        unsigned short semncnt;                /* number of semaphores                */
/* awaiting semval>cval.                */
        unsigned short semzcnt;                /* number of semaphores                */
                                                                /* awaiting semval=0.                */
};
        图1是一个信号灯集合的示意图:

2.2关于信号灯操作的系统调用说明
系统为信号灯操作提供了3个调用:semget, semop, semctl,这些调用都使用了以下头文件:
        #include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
下面是系统调用的详细说明。
2.2.1系统调用semget
作用:创建一个信号灯集合或者访问一个已经存在的信号灯集合。
形式:int semget(key_t key, int nsems, int semflag);
返回值:信号灯集合的标识semid;如果错误返回-1。
描述:
key为信号灯集合的标识号,它是全系统范围内唯一的键值;nsems表示创建的信号灯的个数;semflag指明该信号灯集合的打开方式,它是由一些常数组合(按位或)而成的,见下表:
                表2-1  信号灯调用semget中sem_flg参数选择项
数值(八进制)        符号        描述
0400
0200
0040
0020
0004
0002
01000
02000        SEM_R
SEM_A
SEM_R>>3
SEM_A>>3
SEM_R>>6
SEM_A>>6
IPC_CREAT
IPC_EXCL        拥有者可读
拥有者可写
同组者可读
同组者可写
其他人可读
其他人可写
创建或获取一个信号灯集合
创建一个新的信号灯集合
说明:
1.        设置semflag的IPC_CREAT位,则创建一个信号灯集合,如果该信号灯集合已经存在,则返回其标识符(semid);
2.        设置semflag的IPC_CREAT|IPC_EXCL位,则创建一个新的信号灯集合,如果已经存在则返回错误信息;
3.        只设置IPC_EXCL位而不设置IPC_CREAT位没有任何意义。
2.2.2系统调用semop
作用:对信号灯集合中一个或多个信号灯进行操作
形式:int semop(int semid, struct sembuf *sops, unsigned int nops);
返回值:操作成功返回0,失败返回-1。
描述:
数组sops的每个元素对应一次操作。nops指明执行几次操作。
sembuf是具有如下形式的一个数据结构的数组:
        struct sembuf{
                unsigned short sem_num;                /* semaphore number.                        */
                short                   semop;                /* semaphore operation.                */
                short                   sem_flg;                /* operation flags.                        */
        }
        该结构对应了信号灯的某种操作。
信号灯的sem_num值标明它是信号灯集合的第几个元素,第一个信号灯为0,第二个为1,依次类推。semop确定了对信号灯采取什么样的操作,它可以为负数,正数和零。sem_flg指明操作的执行模式,它有两个标志位:
IPC_NOWAIT(04000):指明以非阻塞方式操作信号灯。
SEM_UNDO(010000): 指明内核为信号灯操作保留恢复值。
System V将信号灯的值semval初始化为0。信号灯值为0时可以使用,为非0时不可使用。对信号灯的操作可以用以下原语来描述:
1.If sem_op>0  Then                 /*sem_op>0对应对信号灯的抢占。*/
semval=semval+sem_op;                /*抢占成功,信号灯当前值加上sem_op*/
2.If sem_op==0 Then                            /*sem_op==0对应对信号灯使用权的请求。*/
               {
                                 If semval==0 Then                /*semval==0表明信号灯可以使用,*/
                                        立即返回;                        /*请求成功.                   */
                         Else                                                /*semval!=0表明信号灯不可使用*/
                                 {
                                        If(sem_flg&IPC_NOWAIT)/*IPC_NOWAIT指明如果信号灯不可使用,*/                                       立即返回;                        /*则不等待,立即返回。*/
                                        Else                                                /*如果信号灯不可使用,则一直等待。*/
                                                进程挂起直到:semval==0;
                                 }
                   }
3.If sem_op<0 Then                                /*sem_op<0对应对信号灯的释放。*/
         {
                  If(semval+sem_op)>=0 Then   /*semval+sem_op>=0表明需要释放信号灯。*/
                                 semval=semval+sem_op;    /*信号灯当前值减去|sem_op|,释放信号灯。*/
                    Else
                  {
        If(sem_flg&IPC_NOWAIT)        /*如果无需释放信号灯,                         */
                                        立即返回;                        /*且IPC_NOWAIT置位,则立即返回。*/
        Else                                                /*挂起等待释放信号灯的条件满足。 */
                                        进程挂起直到:(semval+sem_op)>=0;
               }
   }
        以上原语描述的情况比较复杂,在一般应用中实际只使用二值信号灯,即semval只能为1或0,其操作流程就很容易理解了。举个实际的例子来说明对信号灯的操作。我们创建一个二值信号灯,给信号灯加锁前先要等待信号灯的值变为0,获取信号灯后将其值加1。给信号灯解锁的是直接给信号灯减1。
        加锁的sembuf及其操作如下:
        static struct sembuf sem_lock[2]=
        {
                0,0,0,                                /* sem_lock[0] */
                0,1,SEM_UNDO                        /* sem_lock[1] */
        };
        semop(semid, &sem_lock[0], 2);
        说明:
        该调用执行了两次操作:先等待信号灯的值变为0并获取信号灯操作权,然后将信号灯当前值semval加1,表明对信号灯占用成功。其它进程要使用该信号灯必须先等待semval变为0。
注意内核一次将sembuf中多个操作连续执行完,在这个期间,其它进程无法对该信号灯进行操作。比较以下两个操作的组合与以上操作的区别:
        semop(semid, &sem_lock[0], 1);
        semop(semid, &sem_lock[1], 1);
        虽然这两个操作的组合完成了上面的功能,但对内核而言不一定是连续进行的,在两次操作期间会有其它进程使用该信号灯。因此这两个操作是无效的。
        解锁的sembuf如下:
        static struct sembuf sem_unlock[1]=
        {
                0, -1, (IPC_NOWAIT|SEM_UNDO)
        }
        说明:
        如果当前信号灯的值semval=1,则当前值减1为0,表明信号灯再次可用。因为在我们的程序里是先加锁,后解锁,所以semval一定为1。但是为了避免错误使用时导致程序挂起,一般我们将sem_flg的IPC_NOWAIT位置上,当释放失败时立即返回错误信息。
在上面的例子里面我们使用了sem_flg的SEM_UNDO位。系统为每个操作信号灯的进程维持了一个操作调整值(semaphoreadjustmentvalue),SEM_UNDO标志指示系统在进程退出时恢复该进程使用信号灯之前的信号灯值。SEM_UNDO标志位的作用可以描述如下:
1.        信号灯初始化时调整值一概为0;在信号灯删除时与其相关的调整值一起被删除。
2.        对每个进程,信号灯值增加,调整值等量减小;信号灯值减小,调整值等量增加。
3.        当进程调用exit退出时,内核自动为该进程恢复其操作以前的信号灯值。
        引进SEM_UNDO标志的作用是为了防止当进程异常退出时没有释放信号灯,而其它进程只能永远处于等待状态。
2.2.3 系统调用semctl
作用:提供对信号灯集合中某个信号灯的多种控制功能。
形式:int semctl(int semid, int semnum, int cmd, union semun arg);
返回值:操作成功时根据cmd的不同返回需要的值或0,失败返回-1。
描述:
semid是信号灯集合的标识号,semnum是信号灯号。cmd标识了操作类别。arg用于进行某些操作时存放数据。
semun数据结构如下:
union semnum{
                int semval;                                /*当cmd为SETVAL时有效。                                        */
                struct semid_ds *buf;                /*当cmd为IPC_STAT或IPC_SET时有效。                */
                ushort *array;                                /*当cmd为IPC_GETALL或IPC_SETALL时有效。*/
}
cmd操作包括:
GETVAL:返回信号灯值。
SETVAL:置信号灯值为arg.val。信号灯调整值同时清零。
GETPID:返回sempid。
GETNCNT:返回semncnt。
GETZCNT:返回semzcnt。
GETALL:获取信号灯集合的每个信号灯的值,存入arg.array。
SETALL:置信号灯集合中每个信号灯的值为arg.array的值,对应的调整值同时清零。
IPC_STAT:获取信号灯集合的semid_ds,存入arg.buf。
IPC_SET:将arg.buf数据结构的如下成员赋给信号灯的semid_ds结构:
sem_perm.uid;
sem_perm.gid
sem_perm.mode;                /* 只有低9位有效。 */
                          能够进行此项操作的进程限于超级用户、sem_perm.cuid或sem_perm.uid。
IPC_RMID:删除指定信号灯集合。能够进行此项操作的进程限于超级用户、
   sem_perm.cuid或sem_perm.uid。
3 共享内存的使用
3.1 共享内存的概念
进程间通信(IPC)的几种方法中,管道、命名管道和消息队列传递数据时都需要经过内核缓冲区。而使用共享内存的方法,不同进程之间拷贝数据可以直接从指定内存存取。事实上,共享内存是几种IPC方法中效率最高的一种。
当某个进程正在使用一段共享内存时,其它进程必须等待该操作结束才能使用。这种协调机制可以用信号灯来实现。下面是用信号灯实现共享内存的示意图:

        内核为每个共享内存维护一个如下的数据结构:
        struct shmid_ds{
                struct ipc_perm         shm_perm;        /* 操作权限                                        */
                int                                 shm_segsz;        /* 内存段大小                                */
                struct  tagStruType        shm_Struct;        /* 内存结构和地址                &nbsp …

没有评论 »

linux ipc

十二月 28, 2008 | linux | RSS 2.0

five methods
 1  Shared memory permits processes to communicate by simply reading and
  writing to a specified memory location.
内存共享允许进程通过读写到一个的内存区域来进行交换
 2  Mapped memory is similar to shared memory, except that it is associated with a
  file in the filesystem.
内存映射同样也是内存共享,只不过是和文件系统中的文件相关。两个有联系
3 Pipes permit sequential communication from one process to a related process.
管道允许在两个有联系的进程间有序的交换数据
4   FIFOs are similar to pipes, except that unrelated processes can communicate
  because the pipe is given a name in the filesystem.
fifo 是和管道很像的方式,由于他管道在文件系统中给了名字,不相关的进程可以交换
5  Sockets support communication between unrelated processes even on different
 computers
sockets.支持不相关的进程间,在不同的计算机上进行交流

  Whether they restrict communication to related processes (processes with a
  common ancestor), to unrelated processes sharing the same filesystem, or to any
  computer connected to a network
  Whether a communicating process is limited to only write data or only
  read data   The number of processes permitted to communicate
  Whether the communicating processes are synchronized by the IPC—for
  example, a reading process halts until data is available to read

没有评论 »

春江花月夜

十二月 26, 2008 | linux | RSS 2.0

  春江潮水连海平,海上明月共潮生。
  滟滟随波千万里,何处春江无月明!
  江流宛转绕芳甸,月照花林皆似霰(读作xiàn)。
  空里流霜不觉飞,汀上白沙看不见。
  江天一色无纤尘,皎皎空中孤月轮。
  江畔何人初见月?江月何年初照人?
  人生代代无穷已,江月年年只(一作“望”)相似。
  不知江月待何人,但见长江送流水。
  白云一片去悠悠,青枫浦上不胜愁。
  谁家今夜扁舟子?何处相思明月楼?
  可怜楼上月徘徊,应照离人妆镜台。
  玉户帘中卷不去,捣衣砧上拂(一作“指”)还来。
  此时相望不相闻,愿逐月华流照君。
  鸿雁长飞光不度,鱼龙潜跃水成文。
  昨夜闲潭梦落花,可怜春半不还家。
  江水流春去欲尽,江潭落月复西斜(为了押韵,所以读xiá)。
  斜(这里是句首,不要押韵,所以读xié)月沉沉藏海雾,碣(读作jié)石潇湘无限路。
  不知乘月几人归,落月(一作“花”)摇情满江树
很快的几年就圣诞了,毕业已经一年了难得的2008,难忘的2008真的要结束了,在一年发生了太多的事情,让人难以忘怀。不平凡的一年。太多的事情。数不清的大事。幸运的我,幸运的2008.就要再见了,自己真的要再长一岁了。
难得的境界啊。

没有评论 »

一点思考

十二月 25, 2008 | 心情杂记, 读书 | RSS 2.0

思考解决问题的方法
1 临界点思考法
2 二分法思考解决问题。
3 空间换效率,算法和数据结构的存储空间的平衡点。
4 变换思维思考问题。突破旧思维。
5 贪心法算法。抓主要矛盾。
6 分层思考,分治与递归。
7 纵览全局 思考问题

没有评论 »

Processes Vs Threads

十二月 24, 2008 | c/c++, linux | RSS 2.0

For some programs that benefit from concurrency, the decision whether to use
processes or threads can be difficult. Here are some guidelines to help you decide
which concurrency model best suits your program:
      All threads in a program must run the same executable. A child process, on the
   n
      other hand, may run a different executable by calling an exec function.
      An errant thread can harm other threads in the same process because threads
   n
      share the same virtual memory space and other resources. For instance, a wild
      memory write through an uninitialized pointer in one thread can corrupt
      memory visible to another thread.
      An errant process, on the other hand, cannot do so because each process has a
      copy of the program’s memory space.
      Copying memory for a new process adds an additional performance overhead
   n
      relative to creating a new thread. However, the copy is performed only when
      the memory is changed, so the penalty is minimal if the child process only reads
      memory.
      Threads should be used for programs that need fine-grained parallelism. For
   n
      example, if a problem can be broken into multiple, nearly identical tasks, threads
      may be a good choice. Processes should be used for programs that need coarser
      parallelism.
      Sharing data among threads is trivial because threads share the same memory.
   n
      (However, great care must be taken to avoid race conditions, as described previ-
      ously.) Sharing data among processes requires the use of IPC mechanisms, as
      described in Chapter 5.This can be more cumbersome but makes multiple
      processes less likely to suffer from concurrency bugs.
#include <malloc.h>
#include <pthread.h>
#include <semaphore.h>

struct job {
  /* Link field for linked list.  */
  struct job* next;

  /* Other fields describing work to be done… */
};

/* A linked list of pending jobs.  */
struct job* job_queue;

extern void process_job (struct job*);

/* A mutex protecting job_queue.  */
pthread_mutex_t job_queue_mutex = PTHREAD_MUTEX_INITIALIZER;

/* A semaphore counting the number of jobs in the queue.  */
sem_t job_queue_count;

/* Perform one-time initialization of the job queue.  */

void initialize_job_queue ()
{
  /* The queue is initially empty.  */
  job_queue = NULL;
  /* Initialize the semaphore which counts jobs in the queue.  Its
     initial value should be zero.  */
  sem_init (&job_queue_count, 0, 0);
}

/* Process queued jobs until the queue is empty.  */

void* thread_function (void* arg)
{
  while (1) {
    struct job* next_job;

    /* Wait on the job queue semaphore.  If its value is positive,
       indicating that the queue is not empty, decrement the count by
       one.  If the queue is empty, block until a new job is enqueued.  */
    sem_wait (&job_queue_count);

    /* Lock the mutex on the job queue.  */
    pthread_mutex_lock (&job_queue_mutex);
    /* Because of the semaphore, we know the queue is not empty.  Get
       the next available job.  */
    next_job = job_queue;
    /* Remove this job from the list.  */
    job_queue = job_queue->next;
    /* Unlock the mutex on the job queue, since we’re done with the
       queue for now.  */
    pthread_mutex_unlock (&job_queue_mutex);

    /* Carry out the work.  */
    process_job (next_job);
    /* Clean up.  */
    free (next_job);
  }
  return NULL;
}

/* Add a new job to the front of the job queue.  */

void enqueue_job (/* Pass job-specific data here…  */)
{
  struct job* new_job;

  /* Allocate a new job object.  */
  new_job = (struct job*) malloc (sizeof (struct job));
  /* Set the other fields of the job struct here…  */

  /* Lock the mutex on the job queue before accessing it.  */
  pthread_mutex_lock (&job_queue_mutex);
  /* Place the new job at the head of the queue.  */
  new_job->next = job_queue;
  job_queue = new_job;

  /* Post to the semaphore to indicate another job is available.  If
     threads are blocked, waiting on the semaphore, one will become
     unblocked so it can process the job.  */
  sem_post (&job_queue_count);

  /* Unlock the job queue mutex.  */
  pthread_mutex_unlock (&job_queue_mutex);
}

没有评论 »