posts - 16, comments - 1, trackbacks - 0, articles - 0
  IT博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

2011年10月16日

前台进程就是用户使用的有控制终端的进程,守护进程是从来不需要用户输入的程序,它是一种特许的后台进程。
基本上任何一个程序都可以后台运行,但守护进程是具有特殊要求的程序,比如要脱离自己的父进程,成为自己的会话组长等,这些要在代码中显式地写出来

换句话说,守护进程肯定是后台进程,但反之不成立。守护进程顾名思义,主要用于一些长期运行,守护着自己的职责(监听端口,监听服务等)。我们的系统下就有很多守护进程。
很多系统服务名字后面带个d,就是daemon、守护的意思。另外unistd.h中定义了daemon()这个函数可以把当前进程状态转化为daemon进程。
linux下使用 & 可以使程序进入后台运行模式

posted @ 2011-10-16 21:39 Mr.雷 阅读(555) | 评论 (1)编辑 收藏

2011年9月3日

#include <iostream.h>

//十进制数转换成二进制数字
void fun_1(int n)
{
   if(n<2)   
       cout<<n;
   if(n>=2)  
   {
     fun_1(n/2);
     cout<<n%2;
   }
}

//十进制数字转换成八进制数字
void fun_2(int n)
{
  if(n<8)   
      cout<<n;
  if(n>=8)  
  {
    fun_2(n/8);
    cout<<n%8;
  }
}

//十进制数转换成十六进制数字
void fun_3(int n)
{
  switch(n)
  {
     case 10:   cout<<"A"; break;
     case 11:   cout<<"B"; break;
     case 12:   cout<<"C"; break;
     case 13:   cout<<"D"; break;
     case 14:   cout<<"E"; break;
     case 15:   cout<<"F"; break;
     default:   cout<<n;   
  }
}     

void fun_4(int n)
{
   if(n<16)   
       fun_3(n);
   if(n>=16)  
   {
     fun_4(n/16);
     fun_3(n%16);
   }
}

//主函数
void main()
{ 
    int n;
    cout<<"请输入n的值:  "<<endl;
    cin>>n;
    cout<<"十进制数字转换成二进制,八进制,十六进制数字结果如下:"<<endl;
    fun_1(n);        
    cout<<endl;      //输出结果换行
    fun_2(n);        
    cout<<endl;      
    fun_4(n);       
    cout<<endl;    
} 

输出结果:

posted @ 2011-09-03 21:54 Mr.雷 阅读(514) | 评论 (0)编辑 收藏

2011年8月24日

strcpy(), 字符串拷贝.
char *strcpy(char *strDest, const char *strSrc)
{
    assert((strDest!=NULL) && (strSrc !=NULL));
    char *address = strDest;     
    while( (*strDest++ = * strSrc++) != '\0') 
       NULL ; 
    return address ;       
}

memcpy, 拷贝不重叠的内存块 
void *memcpy(void* pvTo, void* pvFrom, size_t size) //byte是java里的变量类型
{
assert(pvTo != NULL && pvFrom != NULL);
void* pbTo = (byte*)pvTo;
void* pbFrom = (byte*)pvFrom;
/* 内存块重叠吗?如果重叠,就使用memmove */
assert(pbTo>=pbFrom+size || pbFrom>=pbTo+size);
while(size-->0)
    *pbTo++ == *pbFrom++;
return pvTo;
}

void *MemCopy(void *dest,const void *src,size_t count)
{
    char *pDest=static_cast<char *>(dest);
    const char *pSrc=static_cast<const char *>(src);
    if( pDest>pSrc && pDest<pSrc+count )
    {
        for(size_t i=count-1; i<=0; ++i)
        {
            pDest[i]=pSrc[i];
        }
    }
    else
    {
        for(size_t i=0; i<count; ++i)
        {
             pDest[i]=pSrc[i];
        }
    }
    return pDest;
}

void *Memmove(void *Dst, const void*Src,size_t count)
{
assert(Dst && Src);
void* pDst = Dst;
if (Dst<Src && (char*)Dst > (char*)Src + count)
{
while(count--)
{
   *(char*)Dst = *(char*)Src;
   Dst = (char*)Dst + 1;
   Src = (char*)Src + 1;
}
}
else
{
   Dst = (char*)Dst + count - 1;
   Src = (char*)Src + count - 1;
   while(count--)
   {
      *(char*)Dst = *(char*)Src;
      Dst = (char*)Dst -1 ;
      Src = (char*)Src -1 ;
   }
}
return pDst;
}


void* memmove(void *dest, const void *src,size_t n) 

    if (n == 0) return 0; 
    if (dest == NULL) return 0; 
    if (src == NULL)    return 0; 
    char *psrc = (char*)src; 
    char *pdest = (char*)dest; 
    if((dest <= psrc) || (pdest >= psrc + n)) /*检查是否有重叠问题 */ 
        { 
         for(int i=0; i < n; i++) /*正向拷贝*/ 
          { 
           *pdest = *psrc; 
           psrc++; 
           pdest++; 
          } 
        } 
        else /*反向拷贝*/ 
        { 
          psrc += n; 
          pdest += n; 
          for(int i=0;i<n;i++) 
           { 
            psrc--; 
            pdest--; 
            *pdest = *psrc; 
           } 
        } 
   return dest;
}

memset:把buffer所指内存区域的前count个字节设置成字符c

void * Memset(void* buffer, int c, int count)
{
char* pvTo=(char*)buffer;
assert(buffer != NULL);
while(count-->0)
*pvTo++=(char)c;
return buffer;
}

posted @ 2011-08-24 22:50 Mr.雷 阅读(333) | 评论 (0)编辑 收藏

2011年8月20日

当free或delete一个指针的时候,实际上仅仅是让编译器释放内存,但指针本身依然存在。这时它就像是一个迷途指针,处于悬浮状态。当使用语句P=0(NULL)之后,可以把迷途指针改为空指针。不可以直接使用一个迷途指针或者空指针,这样会使得程序造成崩溃。但是同样是崩溃,空指针造成的崩溃相比于迷途指针造成的崩溃是一种可预料的崩溃。调试起来也比较方便。

此外,malloc/free与new/delete的最大区别是前者是库函数而后者是运算符。

posted @ 2011-08-20 11:12 Mr.雷 阅读(899) | 评论 (0)编辑 收藏

2010年11月8日

pthread_t    pthr;

pthread_create(&pthr, NULL, thread_handler, NULL);

...

void* thread_handler(void* arg)

{

    /* do something */

    pthread_join(pthr, NULL);

}


上面的代码不好使,pthread_join不能放在pthread调用的handler内,虽然不报错,但是thread无法正常回收,如果多次创建thread,内存会越来越大(另一种形式的内存泄露)。

正确的做法是在handler外面pthread_join:


pthread_t    pthr;

pthread_create(&pthr, NULL, thread_handler, NULL);

pthread_join(pthr, NULL);

...

void* thread_handler(void* arg)

{

    /* do something */

}


如果不用pthread_join,改用pthread_detach呢?那最方便,但要注意:pthread_detach最好是放在handler里面第一句。


void* thread_handler(void* arg)

{

    pthread_detach(pthr);

    /* do something */

}


如果pthread_create后紧跟pthread_detach,有可能会出错。

posted @ 2010-11-08 16:05 Mr.雷 阅读(2759) | 评论 (0)编辑 收藏

2010年10月28日

 

request是封装client端(也就是用户通过browser)提交的请求数据和属性的对象。 
response是封装web server端响应数据和属性的对象。


我们经常会将pageContext、request、session和application混为一谈,因为它们都可以通过setAttribute()和getAttribute()来设定或读取属性。但它们之间是有别的,它们最大的区别在于使用范围。 

pageContext对象的范围只适用于当前页面范围,即超过这个页面就不能够使用了。所以使用pageContext对象向其它页面传递参数是不可能的。 

request对象的范围是指在一JSP网页发出请求到另一个JSP网页之间,随后这个属性就失效。 

session的作用范围为一段用户持续和服务器所连接的时间,但与服务器断线后,这个属性就无效。比如断网或者关闭浏览器。 

application的范围在服务器一开始执行服务,到服务器关闭为止。它的范围最大,生存周期最长。

session主要功能:验证用户是否登录。在几个页面上都能取得。
request:只有<jsp:forward page=" ">跳转页面才能取得。
application:只要设置一次,所有的网页窗口都可以取得数据。
application session request->都需要跨多个页面
设置过多application 或每一个session保存过多的对象则性能降低
能使用request 就不要使用session 能使用session的就不要使用application

application应用:在线人员统计、在线人员名单列表
pageContext:默认情况下一个页面的保存范围
实际上四种属性范围都是通过pageContext属性完成的
pageContext.setAttribute("name","mldn",PageContext.REQUEST_SCOPE);更改红字的名字得到。
在另外一页用request去接收String name=(String)request.getAttribute("name");<%=name%>;
如果要释放application资源要重新启动服务器
四种属性范围都是依靠pageContext展开的,但是在开发中,往往使用session和request范围最多。

posted @ 2010-10-28 15:24 Mr.雷 阅读(2653) | 评论 (0)编辑 收藏

从Tomcat处理用户请求,我们可以清晰的看到容器Servlet的生命周期管理过程:
  1、客户发出请求—>Web 服务器转发到Web容器Tomcat;
  2、Tomcat主线程对转发来用户的请求做出响应创建两个对象:HttpServletRequest和HttpServletResponse;
  3、从请求中的URL中找到正确Servlet,Tomcat为其创建或者分配一个线程,同时把2创建的两个对象传递给该线程;
  4、Tomcat调用Servlet的servic()方法,根据请求参数的不同调用doGet()或者doPost()方法;
  5、假设是HTTP GET请求,doGet()方法生成静态页面,并组合到响应对象里;
  6、Servlet线程结束,Tomcat将响应对象转换为HTTP响应发回给客户,同时删除请求和响应对象。
  从该过程中,我们可以理解Servlet的生命周期:Servlet类加载(对应第3步);Servlet实例化(对应第3步);调用init方法(对应第3步);调用service()方法(对应4、5步);调用destroy()方法(对应第6步)。

posted @ 2010-10-28 15:17 Mr.雷 阅读(290) | 评论 (0)编辑 收藏

java中private, public,protected的区别

在说明这四个关键字之前,我想就class之间的关系做一个简单的定义,对于继承自己的classbase class可以认为他们都是自己的子女,而对于和自己一个目录下的classes,认为都是自己的朋友。 

 1publicpublic表明该数据成员、成员函数是对所有用户开放的,所有用户都可以直接进行调用
 2privateprivate表示私有,私有的意思就是除了class自己之外,任何人都不可以直接使用,私有财产神圣不可侵犯嘛,即便是子女,朋友,都不可以使用。
 3protectedprotected对于子女、朋友来说,就是public的,可以自由使用,没有任何限制,而对于其他的外部classprotected就变成private

作用域 当前类 同一package 子孙类 其他package 

public       √          √           √            √ 

protected √         √            √            × 

friendly     √         √            ×            × 

private     √         ×            ×             × 

不写时默认为friendly 

posted @ 2010-10-28 14:21 Mr.雷 阅读(593) | 评论 (1)编辑 收藏

2010年10月17日

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 
    1). 并行设备的硬件寄存器(如:状态寄存器) 
    2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 
    3). 多线程应用中被几个任务共享的变量 
    回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。 
    假设被面试者正确地回答了这几个问题(嗯,怀疑这是否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 
    1). 一个参数既可以是const还可以是volatile吗?解释为什么。 
    2). 一个指针可以是volatile 吗?解释为什么。 
    3). 下面的函数有什么错误: 
         int square(volatile int *ptr) 
         { 
              return *ptr * *ptr; 
         } 
    下面是答案: 
    1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 
    2). 是的。尽管这并不很常见。一个例子是当一个中断服务子程序修该一个指向一个buffer的指针时。 
    3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: 
    int square(volatile int *ptr)  
    { 
         int a,b; 
         a = *ptr; 
         b = *ptr; 
         return a * b; 
     } 
    由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下: 
     long square(volatile int *ptr)  
     { 
            int a; 
            a = *ptr; 
            return a * a; 
     } 
讲讲我的理解: (欢迎打板子...~~!) 

关键在于两个地方:      
  
1. 编译器的优化  (请高手帮我看看下面的理解) 

在本次线程内, 当读取一个变量时,为提高存取速度,编译器优化时有时会先把变量读取到一个寄存器中;以后,再取变量值时,就直接从寄存器中取值; 

当变量值在本线程里改变时,会同时把变量的新值copy到该寄存器中,以便保持一致 

当变量在因别的线程等而改变了值,该寄存器的值不会相应改变,从而造成应用程序读取的值和实际的变量值不一致 

当该寄存器在因别的线程等而改变了值,原变量的值不会改变,从而造成应用程序读取的值和实际的变量值不一致  


举一个不太准确的例子:  

发薪资时,会计每次都把员工叫来登记他们的银行卡号;一次会计为了省事,没有即时登记,用了以前登记的银行卡号;刚好一个员工的银行卡丢了,已挂失该银行卡号;从而造成该员工领不到工资  

员工 -- 原始变量地址  
银行卡号 -- 原始变量在寄存器的备份  


2. 在什么情况下会出现(如1楼所说) 

    1). 并行设备的硬件寄存器(如:状态寄存器)  
    2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)  
    3). 多线程应用中被几个任务共享的变量  
     

补充: volatile应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人;

posted @ 2010-10-17 21:55 Mr.雷 阅读(892) | 评论 (0)编辑 收藏

2010年10月13日

信令是交换机之间通信的语言,带外信令是指信令和语音信号的传输走不通的通道。
在很久很久以前(long long ago),那时候人们还处于模拟通信和机械式交换机的时代(纵横或者步进),那时候不存在独立的信令网,交换机之间的“语言交流(信令)”和语音信号在一条传输通道上跑。这就是带内信令。后来发展了,交换机之间的“语言交流(信令)”和语音信号的传输分别走不同的传输通道,建立起独立的信令网,这样信令信号走信令网,语音走语音的传输通道,两者分道扬镳,这就是带外信令!

posted @ 2010-10-13 15:26 Mr.雷 阅读(1682) | 评论 (1)编辑 收藏