Allove Team 致力于移动应用的开发和服务(Android,J2ME,iphone,ophone)

测量程序运行的时间 测量CPU时钟频率

现在的系统基本都是多任务系统,一个时间段内有多个程序在运行。系统通过计时器中断来调
度各任务,一般是10ms调用一次。接下来介绍两种方法来计算单个进程的运行时间。
当进程运行时间相当长时(大于1s),可以直接调用clock()函数(ansi c)。
clock函数返回自进程开始到调用clock所用的clock tick。用clock返回值除以
CLOCKS_PER_SEC 常量,即得到进程所用的秒数。CLOCKS_PER_SEC在Windows是1000,
Linux中是1000 000。clock的实现是:系统在每次计时器中断时判断在执行哪个进程,然
后把那个进程的执行时间记录增加。

clock测量执行时间非常短的程序误差很大。对于测量执行时间非常短的程序的具体运行时
间,可以用INTEL 的RDTSC(Read Time Stamp Counter)指令,它是以时钟周期为单位
(1ns)的,比较精确,它把周期计数寄存器(64位无符号整数,每个时钟周期自动加1)中
的数据赋给edx、eax寄存器,其中edx存高32位,eax存低32位。我们在某段代码前求一次
周期计数器的值spot1,在此代码后面再求一次周期计数器的值spot2,spot2-spot1即得到
运行此代码的时钟周期数,然后转换成秒即可。
下面利用RDTSC测量系统的时钟频率:
#include <stdio.h>
#include <time.h>
#include <windows.h>//为了能调用Sleep()
int main(int argc, char **argv)
{int high0,low0,high1,low1,sleepTime;
 double spot0,spot1;
 sleepTime=10000;//ms,=10seconds
 __asm
//是根据VS反汇编来写的,自己不会Assembly,但是程序运行结果是对的
{rdtsc    mov  dword ptr [high0],edx ;保存高32位到high0    mov
 dword ptr [low0],eax  ;保存低32位到low0 }
//Call Sleep function in Windows
 Sleep(sleepTime);
 __asm {rdtsc    mov  dword ptr [high1],edx ;同上
 mov  dword ptr [low1],eax }
spot0=(double)high0*(1<<30)*4+low0; //把两个32位合成浮点
spot1=(double)high1*(1<<30)*4+low1;
printf("%f4  GHz\r\n",(spot1-spot0)/(1e6*sleepTime)); //即输出时钟频率
return 0;}
结果会有点误差,正常情况下误差很小,我的CPU为1.8xxxGHz,测量也为1.8xxxGHz, 但
是某些运行会出现很奇怪的结果。
要想100%精确的测出一个进程的运行时间应该说是不可能的,不过误差可以很小(0.1%)。
参考:Computer Systems: A Programmer's Perspective,chapter 9

CGI, FASTCGI, XML, XSLT

CGI? 太老了吧!是的,一般人都会说是过时的技术。而且它的并发性很低,很难应付高并发的请求。主要是每次请求服务器都要启动进程,然后处理。而其实CGI程序本身运行的时间很少,尤其是用C开发的CGI,其速度是不用怀疑的。要解决服务器启动进程耗时的问题,利用FASTCGI就可以了。它在CGI的基础上,提供了很好的缓存机制,每次请求不需要建立进程,传说其速度可以达到shtml的水平,差不多是纯静态html的一半。也传说百度、Google也是用C/C++写的,虽然不知道它们具体是怎么做的,但是绝对是离不开C的。

然而,不管是CGI还是FASTCGI,还有个问题就是必须一条一条的输出html,不像php、asp那样直接可以在html中嵌入脚本。解决这个问题,就使用到了XML和XSLT。利用CGI/FASTCGI的高速度来处理数据(XML格式),不涉及显示层,也就是不用手动输出html标签,只要处理XML数据就行了,而处理XML数据还是比较简单的。显示的工作交给XSLT,而且现在大部分的浏览器都支持XSLT,也就是不用在服务器端执行XML的转换工作,直接把数据发送到浏览器,让浏览器转换、显示,这样还可以缓解服务器的压力。而且XSLT还可以执行一些逻辑,比如排序,这样可以把更多的工作分配给浏览器端。

这就是CGI/FASTCGI 与XML、XSLT结合的优势。

Linux系统下的多线程编程

线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期, solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT,当然,也包括Linux。
为什么有了进程的概念后,还要再引入线程呢?使用多线程到底有哪些好处?什么的系统应该选用多线程?我们首先必须回答这些问题。
使用多线程的理由之一是和进程相比,它是一种非常”节俭”的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种”昂贵”的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。

除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:
1) 提高应用程序响应。这对图形界面的程序尤其有意义,当一个操作耗时很长时,整个系统都会等待这个操作,此时程序不会响应键盘、鼠标、菜单的操作,而使用多线程技术,将耗时长的操作(time consuming)置于一个新的线程,可以避免这种尴尬的情况。
2) 使多CPU系统更加有效。操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上。
3) 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
继续阅读 »

J2ME 突破限制和Symbian交互 !

接触J2ME 也有一段时间了,把JME比作一个太监,过之而不及啊。操作系统对J2ME于 的Security 限制真是太多太多了,

欢迎转载   http://blog.allove.org

1.J2ME 访问用户已读的短信

2. J2ME 非认证Midlet 访问网络 PIM ,MULITIMEDIA 等等的安全警告!

3.J2me Midlet开机启动

4.操作系统IPC 进程 Device 信息 电池信息等访问

痛苦久了就会想办法去解决它了,最开始在上unix课程的时候老师 讲到Socket 标准问题,突然间有个灵感,Symbian和Midlet 能否用Socket 通信呢?Socket 既然所有的都遵循标准那么理论上面就是可行的了!

那么实现了Midlet 和操作系统的通信 那么不就可以利用J2ME 去调用那些我们无法触及的应用呢!那不是一下子让J2ME 的限制又扩展了很多了 呵呵

解决思路 就是

一个Symbian Native Services 然后 一个Midlet 访问数据  Native Services 监听来自端口的信息 接受之后进行本地处理 然后将结果返回给Midlet .

以利用J2ME 读取用户短信为例

启动 socket 服务— 监听  —- Midlet 通过Socket 向  Native Services 发送请求  —-》处理数据—-》接受数据—》Midlet处理 更多应用

Symbian 代码 片段 监听Socket

blank.Open(socketServ);
listener.Accept(blank, status);
User::WaitForRequest(status);
if(status != KErrNone) User::Leave(KErrGeneral);
gConsole-&gt;Printf(_L("Accepted connection!!n"));
blank.RecvOneOrMore(buffer, 0, status, dummyLength);
User::WaitForRequest(status);
if(status != KErrNone) User::Leave(KErrGeneral);
if( (buffer[0] == 'p') )
{
ProcessList(&amp;buffer);
gConsole-&gt;Printf(_L("Processing process request!!n"));
}
else if( (buffer[0] == 'c') )
{
gConsole-&gt;Printf(_L("Closing server!!n"));
running = EFalse;
buffer.Copy(KClosing);
}
else
{
gConsole-&gt;Printf(_L("Bad command!!n"));
buffer.Copy(KBadCommand);
}

blank.Write(buffer, status);
User::WaitForRequest(status);
if(status != KErrNone) User::Leave(KErrGeneral);
blank.Close();
}//end of while loop
MIDLET 数据处理

import javax.microedition.io.*;
import java.io.*;

public class ClientConnection {

private NATClientMIDlet midlet;
private static String url = “socket://127.0.0.1:8100″;
//http://blog.allove.org/archives/j2me-fuck-symbian
private String request;

public ClientConnection(NATClientMIDlet midlet) {
this.midlet = midlet;
}

public void sendRequest(String message) {
this.request = message;
new Thread(){
public void run() {
if( request.equals(”") ){
midlet.showAlert(”Enter a request!”);
}else {
sendMessage();
}
}
}.start();
}

public void sendMessage() {
try{
StreamConnection conn = (StreamConnection)Connector.open(url);
OutputStream out = conn.openOutputStream();
byte[] buf = request.getBytes();
out.write(buf, 0, buf.length);
out.flush();
out.close();

byte[] data = new byte[256];
InputStream in = conn.openInputStream();
int actualLength = in.read(data);
String response = new String(data, 0, actualLength);
midlet.textBox.setString(response);

in.close();
conn.close();

}catch(IOException ioe){
ioe.printStackTrace();
midlet.showAlert(”Allove 连接失败”);
}
}

}

这里只提供了解决思想和简单的解决方案 实际应用还得与实际情况进行分析和权衡 找到合适的方案

[C/C++]指针详解(3) — 指针表达式

续:

[C/C++]指针详解(1) — 复杂数据类型与指针

[C/C++]指针详解(2) — 指针运算与运算符

4、指针表达式
一个表达式的结果如果是一个指针,那么这个表达式就叫指针表式。下面是一些指针表达式的例子:
例七:
int a,b;
int array[10];
int *pa;
pa=&a; //&a 是一个指针表达式。
Int **ptr=&pa; //&pa 也是一个指针表达式。
*ptr=&b; //*ptr 和&b 都是指针表达式。
pa=array;
pa++; //这也是指针表达式。
例八:
char *arr[20];
char **parr=arr; //如果把arr 看作指针的话,arr 也是指针表达式
char *str;
str=*parr; //*parr 是指针表达式
str=*(parr+1); //*(parr+1)是指针表达式
str=*(parr+2); //*(parr+2)是指针表达式
继续阅读 »

编程风格:提供代码可读性(Programming Style: Writing for Readability)

There are a lot of ways to solve the same problem in C or C++. This is both good and bad; it is good because you have flexibility. It’s also bad because you have flexibility–the flexibility to choose different solutions to the same problem when it shows up in different places. This is confusing because it obscures the underlying similarity between the problems.

在编写代码的时候有多种方式来提供程序的可读性,但是多种解决方法犹如一把双面剑,多解决方案提供了对于这个问题的灵活性。正因为灵活在不同的地方或者不同的情景就必须使用不同的方法!

继续阅读 »

[C/C++]指针详解(2) — 指针运算与运算符

接《[C/C++]指针详解(1) — 复杂数据类型与指针

一、指针的算术运算
指针可以加上或减去一个整数。指针的这种运算的意义和通常的数值的加减运算的意义是不一样的,以单元为单位。例如:
例二:
char a[20];
int *ptr=(int *)a; //
强制类型转换并不会改变a 的类型
ptr++;

在上例中,指针ptr 的类型是int*,它指向的类型是int,它被初始化为指向整型变量a。接下来的第3 句中,指针ptr 被加了1,编译器是这样处理的:它把指针ptr 的值加上了sizeof(int),在32 位程序中,是被加上了4,因为在32 位程序中,int 占4 个字节。由于地址是用字节做单位的,故ptr 所指向的地址由原来的变量a 的地址向高地址方向增加了4 个字节。由于char 类型的长度是一个字节,所以,原来ptr 是指向数组a 的第0 号元开始的四个字节,此时指向了数组a 中从第4 号单元开始的四个字节。我们可以用一个指针和一个循环来遍历一个数组,看例子: 继续阅读 »

[C/C++]指针详解(1) — 复杂数据类型与指针

一、复杂类型说明

要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解复杂类型其实很简单,一个类型里会出现很多运算符,他们也像普通的表达式一样,有优先级,其优先级和运算优先级一样,所以我总结了一下其原则:

从变量名处起,根据运算符优先级结合,一步一步分析.

下面让我们先从简单的类型开始慢慢分析吧:

int p; //这是一个普通的整型变量

int *p; //首先从P 处开始,先与*结合,所以说明P 是一

//个指针,然后再与int 结合,说明指针所指向

//的内容的类型为int 型.所以P 是一个返回整

//型数据的指针

int p[3]; //首先从P 处开始,先与[]结合,说明P 是一个数

//组,然后与int 结合,说明数组里的元素是整

//型的,所以P 是一个由整型数据组成的数组

int *p[3]; //首先从P 处开始,先与[]结合,因为其优先级

//比*高,所以P 是一个数组,然后再与*结合,说明

//数组里的元素是指针类型,然后再与int 结合,

//说明指针所指向的内容的类型是整型的,所以

//P 是一个由返回整型数据的指针所组成的数组

int (*p)[3]; //首先从P 处开始,先与*结合,说明P 是一个指针

//然后再与[]结合(与”()”这步可以忽略,只是为

//了改变优先级),说明指针所指向的内容是一个

//数组,然后再与int 结合,说明数组里的元素是

//整型的.所以P 是一个指向由整型数据组成的数

//组的指针

int **p; //首先从P 开始,先与*结合,说是P 是一个指针,然

//后再与*结合,说明指针所指向的元素是指针,然

//后再与int 结合,说明该指针所指向的元素是整

//型数据.由于二级指针以及更高级的指针极少用

//在复杂的类型中,所以后面更复杂的类型我们就

//不考虑多级指针了,最多只考虑一级指针.

int p(int); //从P 处起,先与()结合,说明P 是一个函数,然后进入

//()里分析,说明该函数有一个整型变量的参数

//然后再与外面的int 结合,说明函数的返回值是

//一个整型数据

Int (*p)(int); //从P 处开始,先与指针结合,说明P 是一个指针,然后与

//()结合,说明指针指向的是一个函数,然后再与()里的

//int 结合,说明函数有一个int 型的参数,再与最外层的

//int 结合,说明函数的返回类型是整型,所以P 是一个指

//向有一个整型参数且返回类型为整型的函数的指针

int *(*p(int))[3]; //可以先跳过,不看这个类型,过于复杂

//从P 开始,先与()结合,说明P 是一个函数,然后进

//入()里面,与int 结合,说明函数有一个整型变量

//参数,然后再与外面的*结合,说明函数返回的是

//一个指针,,然后到最外面一层,先与[]结合,说明

//返回的指针指向的是一个数组,然后再与*结合,说

//明数组里的元素是指针,然后再与int 结合,说明指

//针指向的内容是整型数据.所以P 是一个参数为一个

//整数据且返回一个指向由整型指针变量组成的数组

//的指针变量的函数.

说到这里也就差不多了,我们的任务也就这么多,理解了这几个类型,其它的类型对我们来说也是小菜了,不过我们一般不会用太复杂的类型,那样会大大减小程序的可读性,请慎用,这上面的几种类型已经足够我们用了.

指针简析:

指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址。要搞清一个指针需要搞清指针的四方面的内容:指针的类型、指针所指向的类型、指针的值或者叫指针所指向的内存区、指针本身所占据的内存区。让我们分别说明。

先声明几个指针放着做例子:

例一:

(1)int*ptr;

(2)char*ptr;

(3)int**ptr;

(4)int(*ptr)[3];

(5)int*(*ptr)[4];

1.指针的类型

从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型。这是指针本身所具有的类型。让我们看看例一中各个指针的类型:

(1)int*ptr;//指针的类型是int*

(2)char*ptr;//指针的类型是char*

(3)int**ptr;//指针的类型是int**

(4)int(*ptr)[3];//指针的类型是int(*)[3]

(5)int*(*ptr)[4];//指针的类型是int*(*)[4]

怎么样?找出指针的类型的方法是不是很简单?

2.指针所指向的类型

当你通过指针来访问指针所指向的内存区时,指针所指向的类型决定了编译器将把那片内存区里的内容当做什么来看待。从语法上看,你只须把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。例如:

(1)int*ptr; //指针所指向的类型是int

(2)char*ptr; //指针所指向的的类型是char

(3)int**ptr; //指针所指向的的类型是int*

(4)int(*ptr)[3]; //指针所指向的的类型是int()[3]

(5)int*(*ptr)[4]; //指针所指向的的类型是int*()[4]

在指针的算术运算中,指针所指向的类型有很大的作用。指针的类型(即指针本身的类型)和指针所指向的类型是两个概念。当你对C 越来越熟悉时,你会发现,把与指针搅和在一起的”类型”这个概念分成”指针的类型”和”指针所指向的类型”两个概念,是精通指针的关键点之一。我看了不少书,发现有些写得差的书中,就把指针的这两个概念搅在一起了,所以看起书来前后矛盾,越看越糊涂。

3.指针的值—-或者叫指针所指向的内存区或地址

指针的值是指针本身存储的数值,这个值将被编译器当作一个地址,而不是一个一般的数值。在32 位程序里,所有类型的指针的值都是一个32 位整数,因为32 位程序里内存地址全都是32 位长。指针所指向的内存区就是从指针的值所代表的那个内存地址开始,长度为si zeof(指针所指向的类型)的一片内存区。以后,我们说一个指针的值是XX,就相当于说该指针指向了以XX 为首地址的一片内存区域;我们说一个指针指向了某块内存区域,就相当于说该指针的值是这块内存区域的首地址。指针所指向的内存区和指针所指向的类型是两个完全不同的概念。在例一中,指针所指向的类型已经有了,但由于指针还未初始化,所以它所指向的内存区是不存在的,或者说是无意义的。以后,每遇到一个指针,都应该问问:这个指针的类型是什么?指针指的类型是什么?该指针指向了哪里?(重点注意)

4 指针本身所占据的内存区

指针本身占了多大的内存?你只要用函数sizeof(指针的类型)测一下就知道了。在32 位平台里,指针本身占据了4 个字节的长度。指针本身占据的内存这个概念在判断一个指针表达式(后面会解释)是否是左值时很有用。

[C/C++]线性表的基本操作 — 初始化和插入

C/C++ — 一个我后悔深入比较晚的领域。汗颜,来迟了,我老了,不行了,今年都二十出头了 、、、

废话少说,一个C++线性表的操作,藏起来不让你们看。O(∩_∩)O哈哈~
(~ o ~)~zZ。。。我很焦虑 。。
为了版面整洁,不让CODE错位所以我要在这里废话 、、、
不要打我,大家当没看见吧 、、、
罪过,罪过。。
看个笑话先:
袋鼠和青蛙去嫖鸡,袋鼠三下两下完事,只听隔壁的青蛙整夜一二三嘿!一二三嘿!袋鼠好羡慕。
次日,袋鼠说:“哇!~~蛙兄,你好棒哦!”
青蛙说:“cao,老子一夜都没跳上床!~~”
好了 ,进入正题:

[C/C++]线性表的基本操作 — 初始化和插入 继续阅读 »

返回顶部