??xml version="1.0" encoding="utf-8" standalone="yes"?>中文字幕在线观看亚洲日韩,久久精品国产亚洲av麻豆小说,亚洲AV本道一区二区三区四区http://www.tkk7.com/huyi2006/category/21597.html 做一个有思想的h,期待与每一位热爱思考的Z?您的x是对我最大的支持?/description>zh-cnWed, 06 Jun 2012 19:35:58 GMTWed, 06 Jun 2012 19:35:58 GMT60C语言中字节对?/title><link>http://www.tkk7.com/huyi2006/articles/380056.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Tue, 05 Jun 2012 10:00:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/380056.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/380056.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/380056.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/380056.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/380056.html</trackback:ping><description><![CDATA[#pragma pack() struct test { char m1; double m4; int m3; }; #pragma pack() #pragma pack(8) struct A { int n; char c; short s; }; struct B { char c; int n; short s; }; #pragma pack() sizeof test:16 sizeof a:8 sizeof b:12 ~译器默认的成员寚w值是8字节Q通过#pragma pack(show)指oQ编译的时候在输出栏会限制默认寚w倹{以上程序运行完通过调试的内存察看功能得到a和b的内存存储区域如下: a的存储区域:0x0012FED0 02 00 00 00 31 00 03 00 b的存储区域:0x0012FEBC 31 00 00 00 02 00 00 00 03 00 00 00 最前面?字节整数是变量的起始地址Q后面是变量的整个存储区域? 现在我们按照 align of member = min( pack setting value, sizeof(member) )的公式分析一下a和b的存储? a的第一个成员n为intQ大ؓ4Qalign of a.n = min(8,sizeof(int) )Q对齐gؓ4。第一个成员相对于l构体v始地址?偏移开始,前四个字?2 00 00 00即ؓn的存储区域,因ؓx86是Little EndianQ低字节在前Q的字节序Q所以第一字节?Q后面三个字?Q我们通常写成0x00000002Q? a的第二个成员c为charQ大ؓ1Qalign of a.c=min(8,sizeof(char))Q对齐gؓ1。c紧接着a后面存储从偏U?开始,满1字节寚w的要求。它的gؓ'1'QASCII码ؓ0x31Q共一个字?1Q? a的第三个成员为shortQ大ؓ2Qalign of a.s=min(8,sizeof(short))Q对齐gؓ2。如果紧接第二个成员从偏U?开始存储就不满?字节寚wQ因此蟩q?个字节,从偏U?字节的地方开始存储,x后两个字?3 00Q? b的第一个成员c为charQ大ؓ1Qalign of a.c=min(8,sizeof(char))Q对齐gؓ1。第一个成员从偏移起始地址0字节开始存储,它的gؓ'1'QASCII码ؓ0x31Q共一个字?1Q? b的第二个成员n为intQ大ؓ4Qalign of a.n = min(8,sizeof(int) )Q对齐gؓ4。如果紧接第二个成员后面从偏U?开始存储就不能4字节寚wQ因此蟩q?个字节,从偏U?字节的地方开始存储,即第5-8的四个字?2 00 00 00Q? b的第三个成员为shortQ大ؓ2Qalign of a.s=min(8,sizeof(short))Q对齐gؓ2。紧接第二个成员从偏U?字节的地方开始存储,?-10两个字节03 00Q? q时有h可能要问QbZ么最后多了两个字?0 00呢?q就是我们下面要讲的Q整个结构体的对齐? 2、align指o align指o可以用于讄各种内置cd、自定义cd如struct、union或class的的寚w方式。指令格式ؓQ__declspec(align(#)) Q?是对齐|取gؓ2?ơ方??192ơ方。在声明自定义类型或内置变量Ӟ如果指定了对齐|则对应变量的起始地址必须是该值的整数倍。除此外Q它q会影响l构体的大小。下面引用两DMSDN关于align的描qͼ Without __declspec(align(#)), Visual C++ aligns data on natural boundaries based on the size of the data, for example 4-byte integers on 4-byte boundaries and 8-byte doubles on 8-byte boundaries. Data in classes or structures is aligned within the class or structure at the minimum of its natural alignment and the current packing setting (from #pragma pack or the /Zp compiler option). 从这D可以看出,如果没有讄align(#)|变量x按照sizeof(x)来对齐v始地址。类或结构体内的成员在类或结构体内部按照min( pack setting value,sizeof(member))来对齐。这个我们在pack指o部分已经分析q? The sizeof value for any structure is the offset of the final member, plus that member's size, rounded up to the nearest multiple of the largest member alignment value or the whole structure alignment value, whichever is greater. 从这D可以看出,align(#)指o会媄响结构体或类的大。ȝ公式为: sizeof(structure) = (l构体最后一个成员的偏移 + sizeof(l构体最后一个成? ) 上取?( n* max( l构体各成员的对齐?align(#)讄的?) ); 其中n为正整数? Ҏ该公式我们分析一下bZ么后面会多两个填充字?? b的最后一个成s偏移?Q大ؓ2Qb中各成员寚w值最大的?Q因为未讄align(#)Q所以上取整的数gؓ4n?+2?的倍数上取整ؓ12。因此后面需要填充两个字节,q样才能使sizeof(b) == 12? <img src ="http://www.tkk7.com/huyi2006/aggbug/380056.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2012-06-05 18:00 <a href="http://www.tkk7.com/huyi2006/articles/380056.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>win32环境C语言实现最基本的DLL~写及调用实例,试通过[原]http://www.tkk7.com/huyi2006/articles/264109.htmlallicallicMon, 06 Apr 2009 05:46:00 GMThttp://www.tkk7.com/huyi2006/articles/264109.htmlhttp://www.tkk7.com/huyi2006/comments/264109.htmlhttp://www.tkk7.com/huyi2006/articles/264109.html#Feedback1http://www.tkk7.com/huyi2006/comments/commentRss/264109.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/264109.html开发环境是DEV C++,采用C语言~写
创徏一个DLL目Q项目名Uhello,DLL~写采用的是DEV C++中的CZ代码

头文件dll.h
#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */


DLLIMPORT void HelloWorld (void);


#endif /* _DLL_H_ */

C文g
dllmain.c
#include <stdio.h>
#include <stdlib.h>

DLLIMPORT void HelloWorld ()
{
    MessageBox (0, "Hello World from DLL!\n", "Hi", MB_ICONINFORMATION);
}


BOOL APIENTRY DllMain (HINSTANCE hInst     /* Library instance handle. */ ,
                       DWORD reason        /* Reason this function is being called. */ ,
                       LPVOID reserved     /* Not used. */ )
{
    switch (reason)
    {
      case DLL_PROCESS_ATTACH:
        break;

      case DLL_PROCESS_DETACH:
        break;

      case DLL_THREAD_ATTACH:
        break;

      case DLL_THREAD_DETACH:
        break;
    }

    /* Returns TRUE on success, FALSE on failure */
    return TRUE;
}

q有要注意的?def文g中指定输出的函数Q编译生成了hello.dll文g

DLL调用部分
dllcall.c
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

HINSTANCE hDLL; //定义DLL包柄
typedef void ( *func)();    //定义函数指针原型
func hello;  //定义函数指针
int main()
{
 if (hDLL == NULL)
    hDLL=LoadLibrary("hello.dll");  //加蝲DLL
 hello = (func)GetProcAddress(hDLL,"HelloWorld"); //获取函数指针
 hello();
 FreeLibrary(hDLL);  //释放DLL
 return 0;
}

~译执行

 



allic 2009-04-06 13:46 发表评论
]]>
linux下C语言实现文g传输的简单实?/title><link>http://www.tkk7.com/huyi2006/articles/263836.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Fri, 03 Apr 2009 15:06:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/263836.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/263836.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/263836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/263836.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/263836.html</trackback:ping><description><![CDATA[ <p>实例来自互联|,q段试代码实现了基本的文g传输原理Q没有实现错误处理?br /><br />//////////////////////////////////////////////////////////////////////////////////////<br />// file_server.c  文g传输序服务器示?br />//////////////////////////////////////////////////////////////////////////////////////<br />//本文件是服务器的代码<br />#include <netinet/in.h>    // for sockaddr_in<br />#include <sys/types.h>    // for socket<br />#include <sys/socket.h>    // for socket<br />#include <stdio.h>        // for printf<br />#include <stdlib.h>        // for exit<br />#include <string.h>        // for bzero<br />/*<br />#include <sys/types.h><br />#include <sys/stat.h><br />#include <fcntl.h><br />#include <unistd.h><br />*/<br />#define HELLO_WORLD_SERVER_PORT    6666 <br />#define LENGTH_OF_LISTEN_QUEUE  20<br />#define BUFFER_SIZE 1024<br />#define FILE_NAME_MAX_SIZE 512<br /><br />int main(int argc, char **argv)<br />{<br />    //讄一个socket地址l构server_addr,代表服务器internet地址, 端口<br />    struct sockaddr_in server_addr;<br />    bzero(&server_addr,sizeof(server_addr)); //把一D内存区的内容全部设|ؓ0<br />    server_addr.sin_family = AF_INET;<br />    server_addr.sin_addr.s_addr = htons(INADDR_ANY);<br />    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);<br /><br />    //创徏用于internet的流协议(TCP)socket,用server_socket代表服务器socket<br />    int server_socket = socket(PF_INET,SOCK_STREAM,0);<br />    if( server_socket < 0)<br />    {<br />        printf("Create Socket Failed!");<br />        exit(1);<br />    }<br />    <br />    //把socket和socket地址l构联系h<br />    if( bind(server_socket,(struct sockaddr*)&server_addr,sizeof(server_addr)))<br />    {<br />        printf("Server Bind Port : %d Failed!", HELLO_WORLD_SERVER_PORT); <br />        exit(1);<br />    }<br />    <br />    //server_socket用于监听<br />    if ( listen(server_socket, LENGTH_OF_LISTEN_QUEUE) )<br />    {<br />        printf("Server Listen Failed!"); <br />        exit(1);<br />    }<br />    while (1) //服务器端要一直运?br />    {<br />        //定义客户端的socket地址l构client_addr<br />        struct sockaddr_in client_addr;<br />        socklen_t length = sizeof(client_addr);<br /><br />        //接受一个到server_socket代表的socket的一个连?br />        //如果没有q接h,q待到有连接请?-q是accept函数的特?br />        //accept函数q回一个新的socket,q个socket(new_server_socket)用于同连接到的客L通信<br />        //new_server_socket代表了服务器和客L之间的一个通信通道<br />        //accept函数把连接到的客L信息填写到客L的socket地址l构client_addr?br />        int new_server_socket = accept(server_socket,(struct sockaddr*)&client_addr,&length);<br />        if ( new_server_socket < 0)<br />        {<br />            printf("Server Accept Failed!\n");<br />            break;<br />        }<br />        <br />        char buffer[BUFFER_SIZE];<br />        bzero(buffer, BUFFER_SIZE);<br />        length = recv(new_server_socket,buffer,BUFFER_SIZE,0);//<font color="#ff0000">q里先接收客L发来的要获取的文件名</font><br />        if (length < 0)<br />        {<br />            printf("Server Recieve Data Failed!\n");<br />            break;<br />        }<br />        char file_name[FILE_NAME_MAX_SIZE+1];<br />        bzero(file_name, FILE_NAME_MAX_SIZE+1);<br />        strncpy(file_name, buffer, strlen(buffer)>FILE_NAME_MAX_SIZE?FILE_NAME_MAX_SIZE:strlen(buffer));<br />//        int fp = open(file_name, O_RDONLY);<br />//        if( fp < 0 )<br />        FILE * fp = fopen(file_name,"r");<br />        if(NULL == fp )<br />        {<br />            printf("File:\t%s Not Found\n", file_name);<br />        }<br />        else<br />        {<br />            bzero(buffer, BUFFER_SIZE);<br />            int file_block_length = 0;<br />//            while( (file_block_length = read(fp,buffer,BUFFER_SIZE))>0)<br /><font color="#0000cc">            while( (file_block_length = fread(buffer,sizeof(char),BUFFER_SIZE,fp))>0)<br />            {<br />                printf("file_block_length = %d\n",file_block_length);<br />                //发送buffer中的字符串到new_server_socket,实际是给客户?br />                if(send(new_server_socket,buffer,file_block_length,0)<0)<br />                {<br />                    printf("Send File:\t%s Failed\n", file_name);<br />                    break;<br />                }<br />                bzero(buffer, BUFFER_SIZE);<br />            }                                                                 //q段代码是@环读取文件的一D|据,在@环调用sendQ发送到客户端,q里一点的TCP每次接受最多是1024字节Q多了就会分片,因此每次发送时量不要过1024字节?/font><br />//            close(fp);<br />            fclose(fp);<br />            printf("File:\t%s Transfer Finished\n",file_name);<br />        }<br />        //关闭与客L的连?br />        close(new_server_socket);<br />    }<br />    //关闭监听用的socket<br />    close(server_socket);<br />    return 0;<br />}<br /><br /><br />//////////////////////////////////////////////////////////////////////////////////////<br />// file_client.c  文g传输客户端程序示?br />//////////////////////////////////////////////////////////////////////////////////////<br />//本文件是客户机的代码<br />#include <netinet/in.h>    // for sockaddr_in<br />#include <sys/types.h>    // for socket<br />#include <sys/socket.h>    // for socket<br />#include <stdio.h>        // for printf<br />#include <stdlib.h>        // for exit<br />#include <string.h>        // for bzero<br />/*<br />#include <sys/types.h><br />#include <sys/stat.h><br />#include <fcntl.h><br />#include <unistd.h><br />*/<br /><br />#define HELLO_WORLD_SERVER_PORT    6666 <br />#define BUFFER_SIZE 1024<br />#define FILE_NAME_MAX_SIZE 512<br /><br />int main(int argc, char **argv)<br />{<br />    if (argc != 2)<br />    {<br />        printf("Usage: ./%s ServerIPAddress\n",argv[0]);<br />        exit(1);<br />    }<br /><br />    //讄一个socket地址l构client_addr,代表客户机internet地址, 端口<br />    struct sockaddr_in client_addr;<br />    bzero(&client_addr,sizeof(client_addr)); //把一D内存区的内容全部设|ؓ0<br />    client_addr.sin_family = AF_INET;    //internet协议?br />    client_addr.sin_addr.s_addr = htons(INADDR_ANY);//INADDR_ANY表示自动获取本机地址<br />    client_addr.sin_port = htons(0);    //0表示让系l自动分配一个空闲端?br />    //创徏用于internet的流协议(TCP)socket,用client_socket代表客户机socket<br />    int client_socket = socket(AF_INET,SOCK_STREAM,0);<br />    if( client_socket < 0)<br />    {<br />        printf("Create Socket Failed!\n");<br />        exit(1);<br />    }<br />    //把客h的socket和客h的socket地址l构联系h<br />    if( bind(client_socket,(struct sockaddr*)&client_addr,sizeof(client_addr)))<br />    {<br />        printf("Client Bind Port Failed!\n"); <br />        exit(1);<br />    }<br /><br />    //讄一个socket地址l构server_addr,代表服务器的internet地址, 端口<br />    struct sockaddr_in server_addr;<br />    bzero(&server_addr,sizeof(server_addr));<br />    server_addr.sin_family = AF_INET;<br />    if(inet_aton(argv[1],&server_addr.sin_addr) == 0) //服务器的IP地址来自E序的参?br />    {<br />        printf("Server IP Address Error!\n");<br />        exit(1);<br />    }<br />    server_addr.sin_port = htons(HELLO_WORLD_SERVER_PORT);<br />    socklen_t server_addr_length = sizeof(server_addr);<br />    //向服务器发vq接,q接成功后client_socket代表了客h和服务器的一个socketq接<br />    if(connect(client_socket,(struct sockaddr*)&server_addr, server_addr_length) < 0)<br />    {<br />        printf("Can Not Connect To %s!\n",argv[1]);<br />        exit(1);<br />    }<br /><br />    char file_name[FILE_NAME_MAX_SIZE+1];<br />    bzero(file_name, FILE_NAME_MAX_SIZE+1);<br />    printf("Please Input File Name On Server:\t");<br />    scanf("%s", file_name);<br />    <br />    char buffer[BUFFER_SIZE];<br />    bzero(buffer,BUFFER_SIZE);<br />    strncpy(buffer, file_name, strlen(file_name)>BUFFER_SIZE?BUFFER_SIZE:strlen(file_name));<br />    //向服务器发送buffer中的数据<br />    send(client_socket,buffer,BUFFER_SIZE,0);<br /><br />//    int fp = open(file_name, O_WRONLY|O_CREAT);<br />//    if( fp < 0 )<br />    FILE * fp = fopen(file_name,"w");<br />    if(NULL == fp )<br />    {<br />        printf("File:\t%s Can Not Open To Write\n", file_name);<br />        exit(1);<br />    }<br />    <br />    //从服务器接收数据到buffer?br />    bzero(buffer,BUFFER_SIZE);<br />    int length = 0;<br /><font color="#0000cc">    while( length = recv(client_socket,buffer,BUFFER_SIZE,0))       //循环接收Q再写到文g<br />    {<br />        if(length < 0)<br />        {<br />            printf("Recieve Data From Server %s Failed!\n", argv[1]);<br />            break;<br />        }<br />//        int write_length = write(fp, buffer,length);<br />        int write_length = fwrite(buffer,sizeof(char),length,fp);<br />        if (write_length<length)<br />        {<br />            printf("File:\t%s Write Failed\n", file_name);<br />            break;<br />        }<br />        bzero(buffer,BUFFER_SIZE);    <br />    }</font><br />    printf("Recieve File:\t %s From Server[%s] Finished\n",file_name, argv[1]);<br />    <br />    close(fp);<br />    //关闭socket<br />    close(client_socket);<br />    return 0;<br />}</p> <img src ="http://www.tkk7.com/huyi2006/aggbug/263836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2009-04-03 23:06 <a href="http://www.tkk7.com/huyi2006/articles/263836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>多种语言socket~程集锦—win32http://www.tkk7.com/huyi2006/articles/263831.htmlallicallicFri, 03 Apr 2009 14:34:00 GMThttp://www.tkk7.com/huyi2006/articles/263831.htmlhttp://www.tkk7.com/huyi2006/comments/263831.htmlhttp://www.tkk7.com/huyi2006/articles/263831.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/263831.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/263831.html借此地方整理以下socket~程的多U语a的实玎ͼsocket可以跨^台的通信Q因此多语言、多q_下的实现有必要了解的。代码都是源自网上,感谢|友的分享?br />
socket~程在windows下的C语言实现Qdev C++下编译通过
~译时设|编译选项 工具-->~译选项-->~译器,N在q接器命令行加入以下命oQ在对话框中?lwsock32
//server.c
#include <stdio.h>
#include <Winsock2.h>
int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
   
    wVersionRequested = MAKEWORD( 1, 1 );
   
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        return;
    }
   
    if ( LOBYTE( wsaData.wVersion ) != 1 ||
    HIBYTE( wsaData.wVersion ) != 1 ) {
        WSACleanup();
        return;
    }
    SOCKET sockSrv=socket(AF_INET,SOCK_STREAM,0);
   
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(6000);
   
    bind(sockSrv,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
   
    listen(sockSrv,5);
   
    SOCKADDR_IN addrClient;
    int len=sizeof(SOCKADDR);
    while(1)
    {
        SOCKET sockConn=accept(sockSrv,(SOCKADDR*)&addrClient,&len);
        char sendBuf[50];
        sprintf(sendBuf,"Welcome %s to here!",inet_ntoa(addrClient.sin_addr));
        send(sockConn,sendBuf,strlen(sendBuf)+1,0);
        char recvBuf[50];
        recv(sockConn,recvBuf,50,0);
        printf("%s\n",recvBuf);
        closesocket(sockConn);
    }
}

//客户端代?br />#include <stdio.h>
#include <Winsock2.h>
int main()
{
    WORD wVersionRequested;
    WSADATA wsaData;
    int err;
   
    wVersionRequested = MAKEWORD( 1, 1 );
   
    err = WSAStartup( wVersionRequested, &wsaData );
    if ( err != 0 ) {
        return;
    }
   
    if ( LOBYTE( wsaData.wVersion ) != 1 ||
        HIBYTE( wsaData.wVersion ) != 1 ) {
        WSACleanup( );
        return;
    }
    SOCKET sockClient=socket(AF_INET,SOCK_STREAM,0);
   
    SOCKADDR_IN addrSrv;
    addrSrv.sin_addr.S_un.S_addr=inet_addr("127.0.0.1");
    addrSrv.sin_family=AF_INET;
    addrSrv.sin_port=htons(6000);
    connect(sockClient,(SOCKADDR*)&addrSrv,sizeof(SOCKADDR));
    send(sockClient,"hello",strlen("hello")+1,0);
    char recvBuf[50];
    recv(sockClient,recvBuf,50,0);
    printf("%s\n",recvBuf);
    closesocket(sockClient);
    WSACleanup();
}



allic 2009-04-03 22:34 发表评论
]]>
Linux下的多线E编E?/title><link>http://www.tkk7.com/huyi2006/articles/256617.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Wed, 25 Feb 2009 06:53:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/256617.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/256617.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/256617.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/256617.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/256617.html</trackback:ping><description><![CDATA[一介lLinux下的多线E编E的文章 <br />1 引言<br />  U程QthreadQ技术早?0q代p提出Q但真正应用多线E到操作pȝ中去Q是?0q代中期Qsolaris是这斚w的佼D。传l的<br />Unix也支持线E的概念Q但是在一个进E(processQ中只允许有一个线E,q样多线E就意味着多进E。现在,多线E技术已l被许多操作p?br />l所支持Q包括Windows/NTQ当Ӟ也包括Linux?br />  Z么有了进E的概念后,q要再引入线E呢Q用多U程到底有哪些好处?什么的pȝ应该选用多线E?我们首先必须回答q些问题?br />  使用多线E的理由之一是和q程相比Q它是一U非?节P"的多d操作方式。我们知道,在Linuxpȝ下,启动一个新的进E必d配给<br />它独立的地址I间Q徏立众多的数据表来l护它的代码Dc堆栈段和数据段Q这是一U?昂贵"的多d工作方式。而运行于一个进E中的多?br />U程Q它们彼此之间用相同的地址I间Q共享大部分数据Q启动一个线E所p的空间远q小于启动一个进E所p的空_而且Q线E间<br />彼此切换所需的时间也q远于q程间切换所需要的旉。据l计Qȝ说来Q一个进E的开销大约是一个线E开销?0倍左叻I当然Q在?br />体的pȝ上,q个数据可能会有较大的区别?br />  使用多线E的理由之二是线E间方便的通信机制。对不同q程来说Q它们具有独立的数据I间Q要q行数据的传递只能通过通信的方式进<br />行,q种方式不仅ҎQ而且很不方便。线E则不然Q由于同一q程下的U程之间׃n数据I间Q所以一个线E的数据可以直接为其它线E所<br />用,q不仅快P而且方便。当Ӟ数据的共享也带来其他一些问题,有的变量不能同时被两个线E所修改Q有的子E序中声明ؓstatic的数<br />据更有可能给多线E程序带来灾难性的打击Q这些正是编写多U程E序时最需要注意的地方?br />  除了以上所说的优点外,不和q程比较Q多U程E序作ؓ一U多d、ƈ发的工作方式Q当然有以下的优点:<br />  1)<br />提高应用E序响应。这对图形界面的E序其有意义,当一个操作耗时很长Ӟ整个pȝ都会{待q个操作Q此时程序不会响应键盘、鼠标?br />菜单的操作,而用多U程技术,耗时长的操作Qtime consumingQ置于一个新的线E,可以避免q种尬的情c?br />  2) 使多CPUpȝ更加有效。操作系l会保证当线E数不大于CPU数目Ӟ不同的线E运行于不同的CPU上?br />  3) 改善E序l构。一个既长又复杂的进E可以考虑分ؓ多个U程Q成为几个独立或半独立的q行部分Q这LE序会利于理解和修改?br />  下面我们先来试~写一个简单的多线E程序?br />2 单的多线E编E?br />  Linuxpȝ下的多线E遵循POSIXU程接口Q称为pthread。编写Linux下的多线E程序,需要用头文gpthread.hQ连接时需要用库libp<br />thread.a。顺便说一下,Linux下pthread的实现是通过pȝ调用cloneQ)来实现的。cloneQ)是Linux所Ҏ的系l调用,它的使用方式cM<br />forkQ关于cloneQ)的详l情况,有兴的读者可以去查看有关文档说明。下面我们展CZ个最单的多线E程?example1.c?br />/* example.c*/<br />#include <stdio.h><br />#include <pthread.h><br />void thread(void)<br />{<br />int i;<br />for(i=0;i<3;i++)<br />printf("This is a pthread.n");<br />}<br />int main(void)<br />{<br />pthread_t id;<br />int i,ret;<br />ret=pthread_create(&id,NULL,(void *) thread,NULL);<br />if(ret!=0){<br />printf ("Create pthread error!n");<br />exit (1);<br />}<br />for(i=0;i<3;i++)<br />printf("This is the main process.n");<br />pthread_join(id,NULL);<br />return (0);<br />}<br />我们~译此程序:<br />gcc example1.c -lpthread -o example1<br />q行example1Q我们得到如下结果:<br />This is the main process.<br />This is a pthread.<br />This is the main process.<br />This is the main process.<br />This is a pthread.<br />This is a pthread.<br />再次q行Q我们可能得到如下结果:<br />This is a pthread.<br />This is the main process.<br />This is a pthread.<br />This is the main process.<br />This is a pthread.<br />This is the main process.<br />  前后两次l果不一Pq是两个U程争夺CPU资源的结果。上面的CZ中,我们使用C两个函数Q  pthread_create和pthread_joinQ?br />q声明了一个pthread_t型的变量?br />  pthread_t在头文g/usr/include/bits/pthreadtypes.h中定义:<br />  typedef unsigned long int pthread_t;<br />  它是一个线E的标识W。函数pthread_create用来创徏一个线E,它的原型为:<br />  extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,<br />  void *(*__start_routine) (void *), void *__arg));<br />  W一个参Cؓ指向U程标识W的指针Q第二个参数用来讄U程属性,W三个参数是U程q行函数的v始地址Q最后一个参数是q行函数<br />的参数。这里,我们的函数thread不需要参敎ͼ所以最后一个参数设为空指针。第二个参数我们也设为空指针Q这样将生成默认属性的U程?br />对线E属性的讑֮和修Ҏ们将在下一节阐q。当创徏U程成功Ӟ函数q回0Q若不ؓ0则说明创建线E失败,常见的错误返回代码ؓEAGAIN<br />和EINVAL。前者表C系l限制创建新的线E,例如U程数目q多了;后者表C第二个参数代表的线E属性值非法。创建线E成功后Q新创徏?br />U程则运行参C和参数四定的函敎ͼ原来的线E则l箋q行下一行代码?br />  函数pthread_join用来{待一个线E的l束。函数原型ؓQ?br />  extern int pthread_join __P ((pthread_t __th, void **__thread_return));<br />  W一个参Cؓ被等待的U程标识W,W二个参Cؓ一个用户定义的指针Q它可以用来存储被等待线E的q回倹{这个函数是一个线E阻?br />的函敎ͼ调用它的函数一直等待到被等待的U程l束为止Q当函数q回Ӟ被等待线E的资源被收回。一个线E的l束有两U途径Q一U是<br />象我们上面的例子一P函数l束了,调用它的U程也就l束了;另一U方式是通过函数pthread_exit来实现。它的函数原型ؓQ?br />  extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));<br />  唯一的参数是函数的返回代码,只要pthread_join中的W二个参数thread_return不是NULLQ这个值将被传递给<br />thread_return。最后要说明的是Q一个线E不能被多个U程{待Q否则第一个接收到信号的线E成功返回,其余调用pthread_join的线E则q?br />回错误代码ESRCH?br />  在这一节里Q我们编写了一个最单的U程Qƈ掌握了最常用的三个函数pthread_createQpthread_join和pthread_exit。下面,我们?br />了解U程的一些常用属性以及如何设|这些属性?br />3 修改U程的属?br />  在上一节的例子里,我们用pthread_create函数创徏了一个线E,在这个线E中Q我们用了默认参数Q即该函数的第二个参数设ؓNUL<br />L。的,对大多数E序来说Q用默认属性就够了Q但我们q是有必要来了解一下线E的有关属性?br />  属性结构ؓpthread_attr_tQ它同样在头文g/usr/include/pthread.h中定义,喜欢q根问底的h可以自己L看。属性g能直接设|?br />Q须使用相关函数q行操作Q初始化的函Cؓpthread_attr_initQ这个函数必dpthread_create函数之前调用。属性对象主要包括是否绑?br />、是否分R堆栈地址、堆栈大、优先。默认的属性ؓ非绑定、非分离、缺?M的堆栈、与父进E同L别的优先U?br />  关于U程的绑定,牉|到另外一个概念:轻进E(LWPQLight Weight<br />ProcessQ。轻q程可以理解为内核线E,它位于用户层和系l层之间。系l对U程资源的分配、对U程的控制是通过轻进E来实现的,一个轻<br />q程可以控制一个或多个U程。默认状况下Q启动多轻q程、哪些轻q程来控制哪些线E是ql来控制的,q种状况即称为非l定的。绑<br />定状况下Q则֐思义Q即某个U程固定?l?在一个轻q程之上。被l定的线E具有较高的响应速度Q这是因为CPU旉片的调度是面向轻q?br />E的Q绑定的U程可以保证在需要的时候它L一个轻q程可用。通过讄被绑定的轻进E的优先U和调度U可以得绑定的U程满诸如?br />时反应之cȝ要求?br />  讄U程l定状态的函数为pthread_attr_setscopeQ它有两个参敎ͼW一个是指向属性结构的指针Q第二个是绑定类型,它有两个取|<br />PTHREAD_SCOPE_SYSTEMQ绑定的Q和PTHREAD_SCOPE_PROCESSQ非l定的)。下面的代码卛_Z一个绑定的U程?br />#include <pthread.h><br />pthread_attr_t attr;<br />pthread_t tid;<br />/*初始化属性|均设为默认?/<br />pthread_attr_init(&attr);<br />pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);<br />pthread_create(&tid, &attr, (void *) my_function, NULL);<br />  U程的分ȝ态决定一个线E以什么样的方式来l止自己。在上面的例子中Q我们采用了U程的默认属性,即ؓ非分ȝ态,q种情况?br />Q原有的U程{待创徏的线E结束。只有当pthread_joinQ)函数q回Ӟ创徏的线E才终止,才能释放自己占用的系l资源。而分ȝE?br />不是q样子的Q它没有被其他的U程所{待Q自p行结束了Q线E也q止了Q马上释攄l资源。程序员应该Ҏ自己的需要,选择适当<br />的分ȝ态。设|线E分ȝ态的函数?pthread_attr_setdetachstateQpthread_attr_t *attr, int<br />detachstateQ。第二个参数可选ؓPTHREAD_CREATE_DETACHEDQ分ȝE)?PTHREAD<br />_CREATE_JOINABLEQ非分离U程Q。这里要注意的一ҎQ如果设|一个线Eؓ分离U程Q而这个线E运行又非常快,它很可能?br />pthread_create函数q回之前q止了Q它l止以后可能将U程号和pȝ资源UMl其他的U程使用Q这栯用pthread_create的线E就?br />C错误的线E号。要避免q种情况可以采取一定的同步措施Q最单的Ҏ之一是可以在被创建的U程里调?br />pthread_cond_timewait函数Q让q个U程{待一会儿Q留够的旉让函数pthread_createq回。设|一D늭待时_是在多线E编E里?br />用的Ҏ。但是注意不要用诸如waitQ)之类的函敎ͼ它们是整个q程睡眠Qƈ不能解决U程同步的问题?br />  另外一个可能常用的属性是U程的优先Q它存放在结构sched_param中。用函数pthread_attr_getschedparam和函?br />pthread_attr_setschedparamq行存放Q一般说来,我们L先取优先U,对取得的g改后再存攑֛厅R下面即是一D늮单的例子?br />#include <stdio.h><br />#include <pthread.h><br />pthread_attr_t attr;<br />pthread_t tid;<br />sched_param param;<br />int newprio=20;<br />pthread_attr_init(&attr);<br />pthread_attr_getschedparam(&attr, &para;m);<br />param.sched_priority=newprio;<br />pthread_attr_setschedparam(&attr, &para;m);<br />pthread_create(&tid, &attr, (void *)myfunction, myarg);<br />  <br />4 U程的数据处?br />  和进E相比,U程的最大优点之一是数据的׃n性,各个q程׃n父进E处沿袭的数据段Q可以方便的获得、修Ҏ据。但q也l多U程<br />~程带来了许多问题。我们必d心有多个不同的进E访问相同的变量。许多函数是不可重入的,卛_时不能运行一个函数的多个拯Q除?br />使用不同的数据段Q。在函数中声明的静态变量常常带来问题,函数的返回g会有问题。因为如果返回的是函数内部静态声明的I间的地址<br />Q则在一个线E调用该函数得到地址后用该地址指向的数据时Q别的线E可能调用此函数q修改了q一D|据。在q程中共享的变量必须?br />关键字volatile来定义,q是Z防止~译器在优化Ӟ如gcc中?OX参数Q改变它们的使用方式。ؓ了保护变量,我们必须使用信号量?br />互斥{方法来保证我们对变量的正确使用。下面,我们逐步介绍处理U程数据时的有关知识?br />4.1 U程数据<br />  在单U程的程序里Q有两种基本的数据:全局变量和局部变量。但在多U程E序里,q有W三U数据类型:U程数据QTSD:<br />Thread-Specific<br />DataQ。它和全局变量很象Q在U程内部Q各个函数可以象使用全局变量一栯用它Q但它对U程外部的其它线E是不可见的。这U数据的?br />要性是显而易见的。例如我们常见的变量errnoQ它q回标准的出错信息。它昄不能是一个局部变量,几乎每个函数都应该可以调用它Q但?br />又不能是一个全局变量Q否则在<br />AU程里输出的很可能是BU程的出错信息。要实现诸如此类的变量,我们必M用线E数据。我们ؓ每个U程数据创徏一个键Q它和这个键<br />相关联,在各个线E里Q都使用q个键来指代U程数据Q但在不同的U程里,q个键代表的数据是不同的Q在同一个线E里Q它代表同样的数<br />据内宏V?br />  和线E数据相关的函数主要?个:创徏一个键Qؓ一个键指定U程数据Q从一个键dU程数据Q删除键?br />  创徏键的函数原型为:<br />  extern int pthread_key_create __P ((pthread_key_t *__key,<br />  void (*__destr_function) (void *)));<br />  W一个参Cؓ指向一个键值的指针Q第二个参数指明了一个destructor函数Q如果这个参C为空Q那么当每个U程l束Ӟpȝ调?br />q个函数来释攄定在q个键上的内存块。这个函数常和函数pthread_once ((pthread_once_t*once_control, void (*initroutine)<br />(void)))一起用,Z让这个键只被创徏一ơ。函数pthread_once声明一个初始化函数Q第一ơ调用pthread_once时它执行q个函数Q以?br />的调用将被它忽略?br />  在下面的例子中,我们创徏一个键Qƈ它和某个数据相兌。我们要定义一个函数createWindowQ这个函数定义一个图形窗口(数据c?br />型ؓFl_Window *Q这是图形界面开发工具FLTK中的数据cdQ。由于各个线E都会调用这个函敎ͼ所以我们用线E数据?br />/* 声明一个键*/<br />pthread_key_t myWinKey;<br />/* 函数 createWindow */<br />void createWindow ( void ) {<br />Fl_Window * win;<br />static pthread_once_t once= PTHREAD_ONCE_INIT;<br />/* 调用函数createMyKeyQ创建键*/<br />pthread_once ( & once, createMyKey) ;<br />/*win指向一个新建立的窗?/<br />win=new Fl_Window( 0, 0, 100, 100, "MyWindow");<br />/* ҎH口作一些可能的讄工作Q如大小、位|、名U等*/<br />setWindow(win);<br />/* 窗口指针值绑定在键myWinKey?/<br />pthread_setpecific ( myWinKey, win);<br />}<br />/* 函数 createMyKeyQ创Z个键Qƈ指定了destructor */<br />void createMyKey ( void ) {<br />pthread_keycreate(&myWinKey, freeWinKey);<br />}<br />/* 函数 freeWinKeyQ释攄?/<br />void freeWinKey ( Fl_Window * win){<br />delete win;<br />}<br />  q样Q在不同的线E中调用函数createMyWinQ都可以得到在线E内部均可见的窗口变量,q个变量通过函数<br />pthread_getspecific得到。在上面的例子中Q我们已l用了函数pthread_setspecific来将U程数据和一个键l定在一赗这两个函数的原<br />型如下:<br />  extern int pthread_setspecific __P ((pthread_key_t __key,__const void *__pointer));<br />  extern void *pthread_getspecific __P ((pthread_key_t __key));<br />  q两个函数的参数意义和用方法是显而易见的。要注意的是Q用pthread_setspecificZ个键指定新的U程数据Ӟ必须自己释放原有<br />的线E数据以回收I间。这个过E函数pthread_key_delete用来删除一个键Q这个键占用的内存将被释放,但同栯注意的是Q它只释N?br />用的内存Qƈ不释放该键关联的U程数据所占用的内存资源,而且它也不会触发函数pthread_key_create中定义的destructor函数。线E数?br />的释攑ֿd释放键之前完成?br />4.2 互斥?br />  互斥锁用来保证一D|间内只有一个线E在执行一D代码。必要性显而易见:假设各个U程向同一个文仉序写入数据,最后得到的l果<br />一定是N性的?br />  我们先看下面一D代码。这是一个读/写程序,它们公用一个缓冲区Qƈ且我们假定一个缓冲区只能保存一条信息。即~冲区只有两个状?br />Q有信息或没有信息?br />void reader_function ( void );<br />void writer_function ( void );<br />char buffer;<br />int buffer_has_item=0;<br />pthread_mutex_t mutex;<br />struct timespec delay;<br />void main ( void ){<br />pthread_t reader;<br />/* 定义延迟旉*/<br />delay.tv_sec = 2;<br />delay.tv_nec = 0;<br />/* 用默认属性初始化一个互斥锁对象*/<br />pthread_mutex_init (&mutex,NULL);<br />pthread_create(&reader, pthread_attr_default, (void *)&reader_function), NULL);<br />writer_function( );<br />}<br />void writer_function (void){<br />while(1){<br />/* 锁定互斥?/<br />pthread_mutex_lock (&mutex);<br />if (buffer_has_item==0){<br />buffer=make_new_item( );<br />buffer_has_item=1;<br />}<br />/* 打开互斥?/<br />pthread_mutex_unlock(&mutex);<br />pthread_delay_np(&delay);<br />}<br />}<br />void reader_function(void){<br />while(1){<br />pthread_mutex_lock(&mutex);<br />if(buffer_has_item==1){<br />consume_item(buffer);<br />buffer_has_item=0;<br />}<br />pthread_mutex_unlock(&mutex);<br />pthread_delay_np(&delay);<br />}<br />}<br />  q里声明了互斥锁变量mutexQ结构pthread_mutex_tZ公开的数据类型,其中包含一个系l分配的属性对象。函?br />pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,调用函?br />pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函?br />pthread_mutexattr_settype用来讄互斥锁属性。前一个函数设|属性psharedQ它有两个取|<br />PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进E中的线E同步,后者用于同步本q程的不同线E。在上面的例子中Q?br />我们使用的是默认属性PTHREAD_PROCESS_<br />PRIVATE。后者用来设|互斥锁cdQ可选的cd有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK?br />PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它们分别定义了不同的上所、解锁机Ӟ一般情况下Q选用最后一个默认属性?br />  pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直臌用pthread_mutex_unlock为止Q均被上锁,卛_一旉只能被一个线E调<br />用执行。当一个线E执行到pthread_mutex_lock处时Q如果该锁此时被另一个线E用,那此U程被阻塞,即程序将{待到另一个线E释放此<br />互斥锁。在上面的例子中Q我们用了pthread_delay_np函数Q让U程睡眠一D|_是Z防止一个线E始l占据此函数?br />  上面的例子非常简单,׃再介l了Q需要提出的是在使用互斥锁的q程中很有可能会出现死锁Q两个线E试囑֐时占用两个资源,q按<br />不同的次序锁定相应的互斥锁,例如两个U程都需要锁定互斥锁1和互斥锁2QaU程先锁定互斥锁1QbU程先锁定互斥锁2Q这时就出现了死?br />。此时我们可以用函?br />pthread_mutex_trylockQ它是函数pthread_mutex_lock的非d版本Q当它发现死锁不可避免时Q它会返回相应的信息Q程序员可以针对死锁<br />做出相应的处理。另外不同的互斥锁类型对死锁的处理不一P但最主要的还是要E序员自己在E序设计注意q一炏V?br />4.3 条g变量<br />  前一节中我们讲述了如何用互斥锁来实现线E间数据的共享和通信Q互斥锁一个明昄~点是它只有两种状态:锁定和非锁定。而条?br />变量通过允许U程d和等待另一个线E发送信LҎ弥补了互斥锁的不I它常和互斥锁一起用。用时Q条件变量被用来d一个线<br />E,当条件不满ӞU程往往解开相应的互斥锁q等待条件发生变化。一旦其它的某个U程改变了条件变量,它将通知相应的条件变量唤?br />一个或多个正被此条件变量阻塞的U程。这些线E将重新锁定互斥锁ƈ重新试条g是否满。一般说来,条g变量被用来进行线扉K的同?br />?br />  条g变量的结构ؓpthread_cond_tQ函数pthread_cond_initQ)被用来初始化一个条件变量。它的原型ؓQ?br />  extern int pthread_cond_init __P ((pthread_cond_t *__cond,__const pthread_condattr_t *__cond_attr));<br />  其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。结构pthread_condattr_t是条?br />变量的属性结构,和互斥锁一h们可以用它来讄条g变量是进E内可用q是q程间可用,默认值是 PTHREAD_<br />PROCESS_PRIVATEQ即此条件变量被同一q程内的各个U程使用。注意初始化条g变量只有未被使用时才能重新初始化或被释放。释放一个条?br />变量的函Cؓpthread_cond_ destroyQpthread_cond_t condQ。 <br />  函数pthread_cond_waitQ)使线E阻塞在一个条件变量上。它的函数原型ؓQ?br />  extern int pthread_cond_wait __P ((pthread_cond_t *__cond,<br />  pthread_mutex_t *__mutex));<br />  U程解开mutex指向的锁q被条g变量condd。线E可以被函数pthread_cond_signal和函?br />pthread_cond_broadcast唤醒Q但是要注意的是Q条件变量只是vd和唤醒线E的作用Q具体的判断条gq需用户l出Q例如一个变量是?br />?{等Q这一Ҏ们从后面的例子中可以看到。线E被唤醒后,它将重新查判断条件是否满I如果q不满Q一般说来线E应该仍d?br />q里Q被{待被下一ơ唤醒。这个过E一般用while语句实现?br />  另一个用来阻塞线E的函数是pthread_cond_timedwaitQ)Q它的原型ؓQ?br />  extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,<br />  pthread_mutex_t *__mutex, __const struct timespec *__abstime));<br />  它比函数pthread_cond_waitQ)多了一个时间参敎ͼl历abstimeD|间后Q即使条件变量不满Q阻塞也被解除?br />  函数pthread_cond_signalQ)的原型ؓQ?br />  extern int pthread_cond_signal __P ((pthread_cond_t *__cond));<br />  它用来释放被d在条件变量cond上的一个线E。多个线E阻塞在此条件变量上Ӟ哪一个线E被唤醒是由U程的调度策略所军_的。要<br />注意的是Q必ȝ保护条g变量的互斥锁来保护这个函敎ͼ否则条g满信号又可能在试条g和调用pthread_cond_wait函数之间被发出,?br />而造成无限制的{待。下面是使用函数pthread_cond_waitQ)和函数pthread_cond_signalQ)的一个简单的例子?br />pthread_mutex_t count_lock;<br />pthread_cond_t count_nonzero;<br />unsigned count;<br />decrement_count () {<br />pthread_mutex_lock (&count_lock);<br />while(count==0)<br />pthread_cond_wait( &count_nonzero, &count_lock);<br />count=count -1;<br />pthread_mutex_unlock (&count_lock);<br />}<br />increment_count(){<br />pthread_mutex_lock(&count_lock);<br />if(count==0)<br />pthread_cond_signal(&count_nonzero);<br />count=count+1;<br />pthread_mutex_unlock(&count_lock);<br />}<br />  countgؓ0Ӟ decrement函数在pthread_cond_wait处被dQƈ打开互斥锁count_lock。此Ӟ当调用到函数<br />increment_countӞpthread_cond_signalQ)函数改变条g变量Q告知decrement_countQ)停止d。读者可以试着让两个线E分别运行这<br />两个函数Q看看会出现什么样的结果?br />  函数pthread_cond_broadcastQpthread_cond_t<br />*condQ用来唤醒所有被d在条件变量cond上的U程。这些线E被唤醒后将再次竞争相应的互斥锁Q所以必d心用这个函数?br />4.4 信号?br />  信号量本质上是一个非负的整数计数器,它被用来控制对公p源的讉K。当公共资源增加Ӟ调用函数sem_postQ)增加信号量。只?br />当信号量值大于0Ӟ才能使用公共资源Q用后Q函数sem_waitQ)减少信号量。函数sem_trywaitQ)和函数pthread_<br />mutex_trylockQ)起同L作用Q它是函数sem_waitQ)的非d版本。下面我们逐个介绍和信号量有关的一些函敎ͼ它们都在头文?br />/usr/include/semaphore.h中定义?br />  信号量的数据cd为结构sem_tQ它本质上是一个长整型的数。函数sem_initQ)用来初始化一个信号量。它的原型ؓQ?br />  extern int sem_init __P ((sem_t *__sem, int __pshared, unsigned int __value));<br />  sem为指向信号量l构的一个指针;pshared不ؓQ时此信号量在进E间׃nQ否则只能ؓ当前q程的所有线E共享;valuel出了信号量?br />初始倹{?br />  函数sem_post( sem_t *sem<br />)用来增加信号量的倹{当有线E阻塞在q个信号量上Ӟ调用q个函数会其中的一个线E不在阻塞,选择机制同样是由U程的调度策略决?br />的?br />  函数sem_wait( sem_t *sem<br />)被用来阻塞当前线E直C号量sem的值大?Q解除阻塞后sem的值减一Q表明公p源经使用后减。函数sem_trywait ( sem_t *sem<br />)是函数sem_waitQ)的非d版本Q它直接信号量sem的值减一?br />  函数sem_destroy(sem_t *sem)用来释放信号量sem?br />  下面我们来看一个用信号量的例子。在q个例子中,一共有4个线E,其中两个U程负责从文件读取数据到公共的缓冲区Q另两个U程?br />~冲取数据作不同的处理(加和乘运)?br />/* File sem.c */<br />#include<br />#include<br />#include<br />#define MAXSTACK 100<br />int stack[MAXSTACK][2];<br />int size=0;<br />sem_t sem;<br />/* 从文?.datd数据Q每Mơ,信号量加一*/<br />void ReadData1(void){<br />FILE *fp=fopen("1.dat","r");<br />while(!feof(fp)){<br />fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);<br />sem_post(&sem);<br />++size;<br />}<br />fclose(fp);<br />}<br />/*从文?.datd数据*/<br />void ReadData2(void){<br />FILE *fp=fopen("2.dat","r");<br />while(!feof(fp)){<br />fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);<br />sem_post(&sem);<br />++size;<br />}<br />fclose(fp);<br />}<br />/*d{待~冲区有数据Q读取数据后Q释攄_l箋{待*/<br />void HandleData1(void){<br />while(1){<br />sem_wait(&sem);<br />printf("Plus:%d+%d=%dn",stack[size][0],stack[size][1],<br />stack[size][0]+stack[size][1]);<br />--size;<br />}<br />}<br />void HandleData2(void){<br />while(1){<br />sem_wait(&sem);<br />printf("Multiply:%d*%d=%dn",stack[size][0],stack[size][1],<br />stack[size][0]*stack[size][1]);<br />--size;<br />}<br />}<br />int main(void){<br />pthread_t t1,t2,t3,t4;<br />sem_init(&sem,0,0);<br />pthread_create(&t1,NULL,(void *)HandleData1,NULL);<br />pthread_create(&t2,NULL,(void *)HandleData2,NULL);<br />pthread_create(&t3,NULL,(void *)ReadData1,NULL);<br />pthread_create(&t4,NULL,(void *)ReadData2,NULL);<br />/* 防止E序q早退出,让它在此无限期等?/<br />pthread_join(t1,NULL);<br />}<br />  在Linux下,我们用命令gcc -lpthread sem.c -o sem生成可执行文件sem?br />我们事先~辑好数据文?.dat?.datQ假讑֮们的内容分别? 2 3 4 5 6 7 8 9 10?-1 -2 -3 -4 -5 -6 -7 -8 -9 -10<br />Q我们运行semQ得到如下的l果Q?br />Multiply:-1*-2=2<br />Plus:-1+-2=-3<br />Multiply:9*10=90<br />Plus:-9+-10=-19<br />Multiply:-7*-8=56<br />Plus:-5+-6=-11<br />Multiply:-3*-4=12<br />Plus:9+10=19<br />Plus:7+8=15<br />Plus:5+6=11<br />  从中我们可以看出各个U程间的竞争关系。而数值ƈ未按我们原先的顺序显C出来这是由于sizeq个数D各个U程L修改的缘故。这<br />也往往是多U程~程要注意的问题?br />5 结<br />  多线E编E是一个很有意思也很有用的技术,使用多线E技术的|络蚂蚁是目前最常用的下载工具之一Q用多U程技术的grep比单U程<br />的grep要快上几倍,cM的例子还有很多。希望大家能用多U程技术写出高效实用的好程序来?br />本文:http://www.china-pub.com 作? 姚?(2001-08-11 09:05:00)<img src ="http://www.tkk7.com/huyi2006/aggbug/256617.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2009-02-25 14:53 <a href="http://www.tkk7.com/huyi2006/articles/256617.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>BTU子文g格式http://www.tkk7.com/huyi2006/articles/241632.htmlallicallicThu, 20 Nov 2008 06:08:00 GMThttp://www.tkk7.com/huyi2006/articles/241632.htmlhttp://www.tkk7.com/huyi2006/comments/241632.htmlhttp://www.tkk7.com/huyi2006/articles/241632.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/241632.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/241632.htmlBTU子文g使用了一U叫bencoding的编码方法来保存数据?br />bencoding现有四种cd的数据:srings(字符?Qintegers(整数)Qlists(列表)Qdictionaries(字典)
~码规则如下Q?br />strings(字符?~码为:<字符串长?gt;Q?lt;字符?gt;
例如Q?:test 表示为字W串"test"
 4:例子 表示为字W串“例子?br />字符串长度单位ؓ字节
没开始或l束标记

integers(整数)~码为:i<整数>e
开始标记iQ结束标Cؓe
例如Q i1234e 表示为整?234
 i-1234e 表示为整?1234
整数没有大小限制
 i0e 表示为整?
 i-0e 为非?br />?开头的为非法如Q?i01234e 为非?/p>

lists(列表)~码为:l<bencoding~码cd>e
开始标Cؓl,l束标记为e
列表里可以包含Q何bencoding~码cdQ包括整敎ͼ字符Ԍ列表Q字典?br />例如Q l4:test5abcdee 表示Z个字W串["test","abcde"]

dictionaries(字典)~码为d<bencoding字符?gt;<bencoding~码cd>e
开始标Cؓd,l束标记为e
关键字必Mؓbencoding字符?br />值可以ؓMbencoding~码cd
例如Q d3:agei20ee 表示为{"age"=20}
 d4:path3:C:\8:filename8:test.txte 表示为{"path"="C:\","filename"="test.txt"}

具体文gl构如下Q?br />全部内容必须都ؓbencoding~码cd?br />整个文gZ个字典结?包含如下关键?br />announce:tracker服务器的URL(字符?
announce-list(可?:备用tracker服务器列?列表)
creation date(可?:U子创徏的时_Unix标准旉格式Q从1970 1??00:00:00到创建时间的U数(整数)
comment(可?:备注(字符?
created by(可?:创徏人或创徏E序的信?字符?
info:一个字典结构,包含文g的主要信息,为分二种情况Q单文gl构或多文gl构
单文件结构如下:
          length:文g长度Q单位字?整数)
          md5sum(可?Q长32个字W的文g的MD5校验和,BT不用这个|只是Z兼容一些程序所保留!(字符?
          name:文g?字符?
          piece length:每个块的大小Q单位字?整数)
          pieces:每个块的20个字节的SHA1 Hash的?二进制格?
多文件结构如下:
          files:一个字典结?br />                 length:文g长度Q单位字?整数)
                 md5sum(可?:同单文gl构中相?br />                 path:文g的\径和名字Q是一个列表结构,如\test\test.txt 列表为l4:test8test.txte
          name:最上层的目录名?字符?
          piece length:同单文gl构中相?br />          pieces:同单文gl构中相同?br />实例Q?br />用记事本打开一?torrent可以看来cM如下内容
d8:announce35:http://www.manfen.net:7802/announce13:creation datei1076675108e4:infod6:lengthi17799e4:name62:MICROSOFT.WINDOWS.2000.AND.NT4.SOURCE.CODE-SCENELEADER.torrent12:piece lengthi32768e6:pieces20:?W ?w?R排T酆ee

很容易看?br />announceQ?a >http://www.manfen.net:7802/announce
creation dateQ?076675108U?02/13/04 20:25:08)
文g?MICROSOFT.WINDOWS.2000.AND.NT4.SOURCE.CODE-SCENELEADER.torrent
文g大小Q?7799字节
文g块大=32768字节



allic 2008-11-20 14:08 发表评论
]]>
函数指针作ؓl构体成员,实现函数注册http://www.tkk7.com/huyi2006/articles/233710.htmlallicallicSat, 11 Oct 2008 02:24:00 GMThttp://www.tkk7.com/huyi2006/articles/233710.htmlhttp://www.tkk7.com/huyi2006/comments/233710.htmlhttp://www.tkk7.com/huyi2006/articles/233710.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/233710.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/233710.html有时我们需要将函数作ؓl构体的成员Q模拟C++cȝ情ŞQ可应用于方法注册?br />#include <stdio.h>

struct a
{
    void (*func)(char *);
};

void hello(char *name)
{
    printf ("hello %s\n",name);
}

int main()
{
    struct a a1;
    a1.func = hello;
    a1.func("illusion");
    system("PAUSE");
    return 0;
}



allic 2008-10-11 10:24 发表评论
]]>
在VC6.0中用sqlite数据?/title><link>http://www.tkk7.com/huyi2006/articles/199720.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sat, 10 May 2008 08:21:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/199720.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/199720.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/199720.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/199720.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/199720.html</trackback:ping><description><![CDATA[ <p>在sqlite.org 上下载得到Windows版本的sqlite,它是以sqlitedll.zip文g提供?其中有sqlite3.def?sqlite3.dll文g,当然可以直接通过LoadLibrary{WIN32API来操作dll,查找其中包含的函?q用这些函?但是一般都 不这么做,原因很简?q样太麻?所以一般先使用LIB命o生成用于链接的lib,然后把sqlite头文件sqlite3.h包含q程序中,<br />q样直接调用 sqlite的API方便多?当然sqlite3.h文g得从sqlite源代码(以sqlite-source-3_3_4.zip文g提供Q中搞到,在源码中sqlite3.hq个头文件是sqlite3.h.in存在的,解压出来Ҏsqlite.h可以了. <br />使用VC++的LIB命o有以下步骤: <br />Q?Q设|VC98中LIB.exe所在的路径Q?<br />D:\MyDoc\db\capi>set path=%path%;"D:\Program Files\Microsoft Visual Studio\VC98\Bin" <br />(2)生成SQLite的lib文gQ?<br />D:\MyDoc\db\capi>LIB /DEF:SQLITE3.DEF /MACHINE:IX86 </p> <p>Microsoft (R) Library Manager Version 6.00.8168 Copyright (C) Microsoft Corp 1992-1998. All rights reserved. Creating library SQLITE.lib and object SQLITE.exp <br />  q样成功地创徏了在WIN32E序中访问sqlite所需要的?可以用于链接WIN32E序. <br />    到此所有用sqlite的准备工作已告罄.现在在MSVC6中新Z个Win32 Console Application工程,把sqlite.dll,sqlite.h和sqlite.lib文g复制到工E文件夹?把sqlite.h文g加入到项 目中,然后在Project Setting的Link中的对象库模块中增加sqlite.lib文g. 或者project->add to project->filesQ选择q个lib文g<br />然后修改加入如下代码卛_: </p> <p>#include <IOSTREAM><br />#include <STRING><br />#include <SSTREAM><br />#include <stdio.h><br />#include "sqlite3.h"</p> <p>using namespace std;</p> <p>sqlite3* pDB;</p> <p>int createTable()<br />{<br />  char* errMsg;<br />  std::string dropTab="drop table test_tab;";<br />  string strSQL= "create table test_tab (f1 int, f2 long, f3 varchar(20));";<br />  int res = sqlite3_exec(pDB,dropTab.c_str(),0,0, &errMsg);<br />  if (res != SQLITE_OK)<br />  {<br />   std::cout << "执行SQL 出错." << errMsg << std::endl;<br />   //return -1;<br />  } </p> <p>  res = sqlite3_exec(pDB,strSQL.c_str(),0,0, &errMsg);</p> <p>  if (res != SQLITE_OK)<br />  {<br />    std::cout << "执行创徏table的SQL 出错." << errMsg << std::endl;<br />    return -1;<br />  }<br />  else<br />  {<br />      std::cout << "创徏table的SQL成功执行."<< std::endl;<br />  }</p> <p>  return 0;<br />}</p> <p>int insert1()<br />{<br />  char* errMsg;</p> <p>  int res = sqlite3_exec(pDB,"begin transaction;",0,0, &errMsg);</p> <p>  for (int i= 1; i < 100; ++i)<br />  {<br />    std::stringstream strsql;<br />    strsql << "insert into test_tab  values(";<br />    strsql  << i << ","<< (i+10) <<",'huyi'"<< ");";<br />    std::string str = strsql.str();<br />    cout << str <<endl;<br />    res = sqlite3_exec(pDB,str.c_str(),0,0, &errMsg);<br />    if (res != SQLITE_OK)<br />    {<br />      std::cout << "执行SQL 出错." << errMsg << std::endl;<br />      return -1;<br />    }<br />  }<br />  res = sqlite3_exec(pDB,"commit transaction;",0,0, &errMsg);<br />  std::cout << "SQL成功执行."<< std::endl;<br />  return 0; <br />}</p> <p> <br />int select1()<br />{<br />  char* errMsg;<br /> int nrow = 0, ncolumn = 0;<br /> char **azResult; //二维数组存放l果<br />  string strSQL= "select * from test_tab;";<br />     /*<br />  int res = sqlite3_exec(pDB,strSQL.c_str(),0,0, &errMsg);</p> <p>  if (res != SQLITE_OK)<br />  {<br />    std::cout << "执行SQL 出错." << errMsg << std::endl;<br />    return -1;<br />  }<br />  else<br />  {<br />       std::cout << "SQL成功执行."<< std::endl;<br />  }<br />  */<br />  sqlite3_get_table(pDB, strSQL.c_str(), &azResult, &nrow, &ncolumn, &errMsg);<br />     int i = 0;<br />  for( i=0 ; i<( nrow + 1 ) * ncolumn ; i++ )<br />  {<br />   if (i>0 && i%ncolumn==0)<br />    printf("\n");<br />      printf( "%s ",azResult[i]);<br />  }<br />         printf("\n");<br />  //释放?azResult 的内存空?br />  sqlite3_free_table( azResult );<br />  sqlite3_close(pDB); //关闭数据?br />  return 0;<br />}</p> <p>int main(int argc, char* argv[])<br />{<br />  if (argc < 2)<br />  {<br />    std::cout << "误入命令行参数Qsqlite数据库名." << std::endl;<br />    return 0;<br />  }</p> <p>  int res = sqlite3_open(argv[1], &pDB);</p> <p>  if( res ){<br />    std::cout << "Can't open database: "<< sqlite3_errmsg(pDB);<br />    sqlite3_close(pDB);<br />    return -1;<br />  }<br />  res = createTable();<br />  if (res != 0)<br />  {<br />      return 0;<br />  }<br />  res = insert1();<br />  if (res != 0)<br />  {<br />      return 0;<br />  }<br />  select1();<br />   return 0;<br />}<br /></p> <img src ="http://www.tkk7.com/huyi2006/aggbug/199720.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-05-10 16:21 <a href="http://www.tkk7.com/huyi2006/articles/199720.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>判断一个数是否是素?/title><link>http://www.tkk7.com/huyi2006/articles/192024.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 10 Apr 2008 15:39:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/192024.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/192024.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/192024.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/192024.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/192024.html</trackback:ping><description><![CDATA[int prime(int m) <br />{<br />   int i,k;   <br />   k=sqrt(m); <br />   for(i = 2; i < k; i++) <br />   if(m % i == 0)<br />      return 0; <br />return 1; <br />} <img src ="http://www.tkk7.com/huyi2006/aggbug/192024.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-04-10 23:39 <a href="http://www.tkk7.com/huyi2006/articles/192024.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ZC语言的内存池设计与实现[转]http://www.tkk7.com/huyi2006/articles/192023.htmlallicallicThu, 10 Apr 2008 15:26:00 GMThttp://www.tkk7.com/huyi2006/articles/192023.htmlhttp://www.tkk7.com/huyi2006/comments/192023.htmlhttp://www.tkk7.com/huyi2006/articles/192023.html#Feedback1http://www.tkk7.com/huyi2006/comments/commentRss/192023.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/192023.html

介绍Q?/p>

       设计内存池的目标是ؓ了保证服务器长时间高效的q行Q通过对申L间小而申请频J的对象q行有效理Q减内存碎片的产生Q合理分配管理用户内存,从而减系l中出现有效I间_Q而无法分配大块连l内存的情况?/p>

目标Q?/p>

    此次设计内存池的基本目标Q需要满线E安全性(多线E)Q适量的内存泄露越界检查,q行效率不太低于malloc/free方式Q实现对4-128字节范围内的内存I间甌的内存池理Q非单一固定大小对象理的内存池Q?/p>

内存池技术设计与实现

    本内存池的设计方法主要参考SGI的alloc的设计方案,Z适合一般的应用Qƈ在alloc的基上做一些简单的修改?/p>

    Mempool的内存池设计Ҏ如下Q也可参考候捷《深入剖析STL》)

    从系l申请大块heap内存Q在此内存上划分不同大小的区块,q把h相同大小的区块连接v来,l成一个链表。比如A大小的块Q组成链表LQ当甌A大小Ӟ直接从链表L头部Q如果不为空Q上取到一块交l申误,当释放A大小的块Ӟ直接挂接到L的头部。内存池的原理比较简单,但是在具体实现过E中大量的细节需要注意?/p>

    1Q字节对齐?/p>

    Z方便内存池中对象的管理,需要对甌内存I间的进行调_在Mempool中,字节寚w的大ؓ最接近8倍数的字节数。比如,用户甌5个字节,Mempool首先会把它调整ؓ8字节。比如申?2字节Q会调整?4Q对比关pd?/p>

序号

寚w字节

范围

0

8

1-8

1

16

9-16

2

24

17-24

3

32

25-32

4

40

33-40

5

48

41-48

6

56

49-56

7

64

57-64

8

72

65-72

9

80

73-80

10

88

81-88

11

96

89-96

12

104

97-104

13

112

105-112

14

120

113-120

15

128

121-128

Q图1Q?/p>

对于过128字节的申P直接调用malloc函数甌内存I间。这里设计的内存池ƈ不是Ҏ有的对象q行内存理Q只是对甌内存I间,而申请频J的对象q行理Q对于超q?28字节的对象申P不予考虑。这个需要与实际目l合Qƈ不是固定不变的。实现对齐操作的函数如下

static size_t round_up(size_t size)
{
        return (((size)+7) &~ 7);// ?字节寚w
}

2Q构建烦引表

内存池中理的对象都是固定大,现在要管?-128字节的范围内的对象申L_除了采用上面提到的字节对齐外Q还需要变通一下,q就是徏立烦引表Q做法如下;
static _obj*  free_list[16];
创徏一个包?6个_obj*指针的数l,关于_objl构后面详细讲解。free_list[0]记录所有空闲空间ؓ8字节的链表的首地址Qfree_list[1]对应16字节的链表,free_list[2]对应24字节的列表。free_list中的下标和字节链表对应关pd考图1中的“序号”和“对齐字节”之间的关系。这U关p,我们很容易用法计算出来。如?/p>

static size_t freelist_index(size_t size)
{
        return (((size)+7)/7-1);// ?字节寚w
}

    所以,q样当用LL间AӞ我们只是通过上面单的转换Q就可以跌{到包含A字节大小的空闲链表上,如下Q?br />_obj** p = free_list[freelist_index(A)];

3:构徏I闲链表

通过索引表,我们知道mempool中维持着16条空闲链表,q些I闲链表中管理的I闲对象大小分别?Q?6Q?4Q?2Q?0?28。这些空闲链表链接v来的方式完全相同。一般情况下我们构徏单链表时需要创建如下的一个结构体?/p>

struct Obj
{
    Obj *next;
    Char* p;
    Int iSize;
}

next指针指向下一个这Ll构Qp指向真正可用I间,iSize用于只是可用I间的大,在其他的一些内存池实现中,q有更复杂的l构体,比如q包括记录此l构体的上l构体的指针Q结构体中当前用空间的变量{,当用LL间时Q把此结构体d的用LL间中去,比如用户甌12字节的空_可以q样?/p>

Obj *p = (Obj*)malloc(12+sizeof(Obj));
p->next = NULL;
p->p = (char*)p+sizeof(Obj);
p->iSize = 12;

但是Q我们ƈ没有采用q种方式Q这U方式的一个缺点就是,用户甌空间时Q内存池加料太多了。比如用L?2字节Ӟ而真实情冉|内存池向内存甌?2+ sizeof(Obj)=12+12=24字节的内存空_q样费大量内存用在标记内存I间上去Qƈ且也没有体现索引表的优势。Mempool采用的是union方式

union Obj
{
    Obj *next;
    char client_data[1];
}

q里除了把上面的struct修改为unionQƈ把int iSizeLQ同时把char*pQ修改ؓchar client_data[1]Qƈ没有做太多的修改。而优势也恰恰体现在这里。如果采用struct方式Q我们需要维护两条链表,一条链表是Q已分配内存I间链表Q另一条是未分配(I闲Q空间链表。而我们用烦引表和unionl构体,只需要维护一条链表,x分配I间链表。具体如?/p>

索引表的作用有两?Q如上所_l护16条空闲链?Q变相记录每条链表上I间的大,比如下标?的烦引表内维持着是大ؓ24字节的空闲链表。这h们通过索引表减在l构体内记录p所指向I间大小的iSize变量。从而减?个字节?/p>

Union的特性是Q结构内的变量是互斥存在的。再q行状态下Q只是存在一U变量类型。所以在q里sizeof(Obj)的大ؓ4Q难道这里我们也需要把q?字节也加到用LL间中dQ其实不是,如果q样Q我们又Ҏ了union的特性?/p>

当我们构建空闲分配链表时Q我们通过next指向下一个unionl构体,q样我们不用p指针。当把这个结构体分配出去Ӟ我们直接q回client_data的地址Q此时client_data正好指向甌I间的首字节。所以这P我们׃用在用户甌I间上添加Q何东ѝ?/p>


?

    Obj的连接方式如上所C,q样我们无需为用LL间添加Q何内宏V  ?/p>

4Q记录申L间字节数

如果采用面向对象方式Q或者我们在释放内存池的I间时能够明知道释攄间的大小Q无需采用q种方式?/p>


?

在C语言中的free没有传递释攄间大,而可以正释放,在这里也是模仿这U方式,采用q种记录甌I间大小的方式去释放内存。用LL?1操作在字节寚w之前执行Q找到合适空间后Q把首字节改写ؓ甌I间的大,当然1个字节最多纪?56个数Q如果项目需要,可以讄为shortcd或者intcdQ不q这样就需要占用用h较大的空间。当释放内存I间Ӟ首先dq个字节Q获取空间大,q行释放。ؓ了便于对大于128字节对象的大进行合适的释放Q同时也对大?28字节的内存申Pd1字节记录大小。所以现在这里限制了用户内存甌I间不得大于255字节Q不q现在已l满项目要求。当然也可以修改为用shortcd记录甌I间的大?/p>

    // 甌
    *(( unsigned char *)result) = (size_t)n;
    unsigned char * pTemp = (unsigned char*)result;
    ++pTemp;
    result = (_obj*)pTemp;
    return result;

    // 释放
    unsigned char * pTemp = (unsigned char *)ptr;
    --pTemp;
    ptr = (void*)pTemp;
    n = (size_t)(*( unsigned char *)ptr);

5Q内存池的分配原?/p>

在内存池的设计中Q有两个重要的操作过E?Qchunk_allocQ申请大块内存,2Qrefill回填操作Q内存池初始化化时ƈ不是为烦引表中的每一w创徏I闲分配链表Q这个过E会推迟刎ͼ只有用户提取h时才会创L分配链表。详l参考如下代码(在sgi中stl_alloc.h文g中你也可以看到这两个函数Q,主要步骤在注释中已经说明?/p>

/**
* @bri: 甌大块内存Qƈq回size*(*nobjs)大小的内存块
* @param: size,round_up寚w后的大小,nobjs
* @return: q回指向W一个对象内存指?br />*/
static char* chunk_alloc(size_t size, int *nobjs)
{
     /**< q回指针 */
     char* __result;
     /**< 甌内存块大?*/
     size_t __total_bytes = size *(*nobjs);
     /**< 当前内存可用I间 */
     size_t __bytes_left = _end_free - _start_free;

     /**< 内存池中q有大片可用内存 */
     if (__bytes_left >= __total_bytes)
     {
         __result = _start_free;
         _start_free += __total_bytes;
         return (__result);
     }
     /**< 臛_q有一个对象大的内存I间 */
     else if (__bytes_left >= size)
     {
         *nobjs = (int)(__bytes_left/size);
         __total_bytes = size * (*nobjs);
         __result = _start_free;
         _start_free += __total_bytes;
         return (__result);
     }
     /**< 内存池中没有MI间 */
     else
     {
         /**< 重新甌内存池的大小 */
         size_t __bytes_to_get = 2 * __total_bytes + round_up(_heap_size >> 4);
         /**< 把内存中剩余的空间添加到freelist?*/
         if(__bytes_left > 0)
         {
              _obj *VOLATILE* __my_free_list = 
                   _free_list + freelist_index(__bytes_left);
              ((_obj*)_start_free)->free_list_link =
*__my_free_list;
              *__my_free_list = (_obj*)_start_free;
         }
         // 甌新的大块I间
         _start_free = (char*)malloc(__bytes_to_get);
         /*=======================================================================*/
         memset(_start_free,0,__bytes_to_get);
         /*=======================================================================*/
         // pȝ内存已经无可用内存,那么从内存池中压~内?br />         if(0 == _start_free)
         {
              size_t __i;
              _obj *VOLATILE* __my_free_list;
              _obj *__p;
              /**< 从freelist中逐项查可用空?此时只收集比size对象大的内存I间) */
              for (__i = size; __i <= (size_t)__MAX_BYTES; __i += __ALIGN)
              {
                   __my_free_list = _free_list + freelist_index(__i);
                   __p = *__my_free_list;
                   /**< 扑ֈI闲?*/
                   if (__p != 0)
                   {
                       *__my_free_list = __p->free_list_link;
                       _start_free = (char*)__p;
                       _end_free = _start_free + __i;
                       return (chunk_alloc(size,nobjs));
                   }
              }
              _end_free = 0;
              /**< 再次甌内存Q可能触发一个异?*/
              _start_free = (char*)malloc(__bytes_to_get);
         }
         /**< 记录当前内存池的定w */
         _heap_size += __bytes_to_get;
         _end_free = _start_free + __bytes_to_get;
         return (chunk_alloc(size,nobjs));
     }
}

/*=======================================================================*/
/**
 * @bri: 填充freelist的连接,默认填充20?br /> * @param: __nQ填充对象的大小Q?字节寚w后的value
 * @return: I闲
 */
static void* refill(size_t n)
{
     int __nobjs = 20;
     char* __chunk = (char*)chunk_alloc(n, &__nobjs);
     _obj *VOLATILE* __my_free_list;
     _obj *VOLATILE* __my_free_list1;
     _obj * __result;
     _obj * __current_obj;
     _obj * __next_obj;
     int __i;
     // 如果内存池中仅有一个对?br />     if (1 == __nobjs) 
         return(__chunk);
     __my_free_list = _free_list + freelist_index(n);
     /* Build free list in chunk */
     __result = (_obj*)__chunk;
     *__my_free_list = __next_obj = (_obj*)(__chunk + n);
     __my_free_list1 = _free_list + freelist_index(n);
     for (__i = 1;; ++__i)
     {
         __current_obj = __next_obj;
         __next_obj = (_obj*)((char*)__next_obj+n);
         if(__nobjs - 1 == __i)
         {
              __current_obj->free_list_link = 0;
              break;
         }else{
              __current_obj->free_list_link = __next_obj;
         }
     }
     return(__result);
}

l过上面操作后,内存池可能会成ؓ如下的一U状态。从图上我们可以看到Q已l构Z8Q?4Q?8Q?28字节的空闲分配链表,而其他没有分配空闲分配链表的他们的指针都指向NULL。我们通过判断索引表中的指针是否ؓNULLQ知道是否已l构建空闲分配表或者空闲分配表是否用完Q如果此处指针ؓNULLQ我们调用refill函数Q重新申?0个这样大的内存I间Qƈ把他们连接v来。在refill函数内,我们要查看大内存中是否有可用内存Q如果有Qƈ且大合适,p回给refill函数?br />


?

 

    6Q线E安?br />    采用互斥体,保证U程安全?br />
内存池测?/p>

    内存池的试主要分两部分试1Q单U程下malloc与mempool的分配速度Ҏ2Q多U程下malloc和mempool的分配速度ҎQ我们分?Q?0Q?6个线E进行测试了?br />    试环境Q操作系l:windows2003+sp1QVC7.1+sp1Q硬件环境:intel(R) Celeron(R) CPU 2.53GHz,512M物理内存?br />
    甌内存I间讑֮如下
#define ALLOCNUMBER0 4
#define ALLOCNUMBER1 7
#define ALLOCNUMBER2 23
#define ALLOCNUMBER3 56
#define ALLOCNUMBER4 10
#define ALLOCNUMBER5 60
#define ALLOCNUMBER6 5
#define ALLOCNUMBER7 80
#define ALLOCNUMBER8 9
#define ALLOCNUMBER9 100

    Malloc方式和mempool方式均用如上数据进行内存空间的甌和释放。申误E,每次循环甌释放上述数据20?br />    我们对malloc和mempoolQ分别进行了如下甌ơ数的测试(单位ZQ?/p>

2

10

20

30

40

50

80

100

150

200

malloc和mempool在单U程Q多U程QreleaseQdebug版的各种试数据QŞ成如下的l计?


?

可以看到mempool无论在多U程q是在单U程情况下,mempool的速度都优于malloc方式的直接分配?/p>

    Malloc方式debug模式下,在不同的U程下,q行旉如下Q通过囄可知Qmalloc方式Q在debug模式下,甌I间的速度和多U程的关pM大。多U程方式Q要略快于单U程的运行实现?/p>


?

    Malloc方式release模式试l果如下?/p>


?

多线E的优势Q逐渐体现出来。当执行200wơ申请和释放Ӟ多线E要比单U程?500ms左右Q?Q?0Q?6个线E之间的差别q不是特别大。不q整体感?个线E的q行旉要稍微高?0Q?6个线E的情况下,意味着q程中线E越多用在线E切换上的时间就多?/p>

下面是mempool在debug试l果


?

    下面是mempool在release模式下的试l果


?

    以上所有统计图中所用到的数据,是我们测试三ơ后q_倹{?/p>

通过上面的测试,可以知道mempool的性能基本上超q直接malloc方式Q在200wơ申请和释放的情况下Q单U程release版情况下Qmempool比直接malloc?10倍。而在4个线E情况下Qmempool要比直接malloc?倍左叟뀂以上测试只是申请速度的测试,在不同的压力情况下,试l果可能会不同,试l果也不能说明mempool方式比malloc方式E_?br />
    结Q内存池基本上满_期设计目标,但是她ƈ不是完美的,有缺P比如,不能甌大于256字节的内存空_无内存越界检查,无内存自动回~功能等。只是这些对我们的媄响还不是那么重要?/p>

׃q是一个公叔R目,代码涉及版权Q所以不能发布出来。如果你惛_自己的内存池Q可以与我联pugg_xchj#hotmail.com.



allic 2008-04-10 23:26 发表评论
]]>
[ȝ]软g工程师笔试题目(C++Q?http://www.tkk7.com/huyi2006/articles/191083.htmlallicallicSun, 06 Apr 2008 11:02:00 GMThttp://www.tkk7.com/huyi2006/articles/191083.htmlhttp://www.tkk7.com/huyi2006/comments/191083.htmlhttp://www.tkk7.com/huyi2006/articles/191083.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/191083.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/191083.html阅读全文

allic 2008-04-06 19:02 发表评论
]]>
cache和volatie变量的关p?/title><link>http://www.tkk7.com/huyi2006/articles/189444.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sat, 29 Mar 2008 05:30:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/189444.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/189444.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/189444.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/189444.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/189444.html</trackback:ping><description><![CDATA[有volatie修饰的变量,每次操作旉循下面动作: <br />从内存取值?--> 攑օ寄存器?---> 操作 ---->写回内存 <br />没有volatie修饰的变量,操作<b>可能</b>遵@Q可能就是不是所有情况都如此Q: <br />从内存取值?--> 攑օ寄存器?---> W一ơ操作?----> W二ơ操作(此时仍操作寄存器中的| ……?--->WNơ操作?--->写回内存 <br /><br /><br />volatile变量的修改要求即时被所有cpu可见Q所以会要求cache一致性。对一些weak memory model的cpuQ还有对memory access order的限制?br /><img src ="http://www.tkk7.com/huyi2006/aggbug/189444.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-03-29 13:30 <a href="http://www.tkk7.com/huyi2006/articles/189444.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>二维数组传递参?/title><link>http://www.tkk7.com/huyi2006/articles/187992.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Sun, 23 Mar 2008 02:02:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/187992.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/187992.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/187992.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/187992.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/187992.html</trackback:ping><description><![CDATA[ <p>二维数组的传?br />二数组传递参数时Q不能以一个二U指针的方式Q以二指针的方式只传递了q个二数组的首地址Q但没有带出q个二维数组各元素的地址Q编译器不能通过二指针的移动寻扑օ元素。对于二U数l要用数l指针的形式传参</p> <p>#include <stdio.h><br />void print_arr (char (*a)[4])<br />{<br />    int i;<br />    for(i = 0; i < 3; i++)<br />    printf("%s\n", a[i]);<br />}</p> <p>int main()<br />{<br />    char *str_arr[3][4] = {"yes", "no", "uncertain"};<br />    print_arr (str_arr);<br />    return 0;<br />}</p> <p>如果要以二指针的Ş式传参,可以在定义ؓ字符串指针数l的形式<br />char *str_arr[] = {"yes", "no", "uncertain"};<br />void print_arr (char **a)<br />{<br />    int i;<br />    for (i=0; i<3;i++)<br />    printf("%s\n", *(a+1));<br />}<br /></p> <img src ="http://www.tkk7.com/huyi2006/aggbug/187992.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-03-23 10:02 <a href="http://www.tkk7.com/huyi2006/articles/187992.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>|络套接字结构体http://www.tkk7.com/huyi2006/articles/187777.htmlallicallicFri, 21 Mar 2008 11:13:00 GMThttp://www.tkk7.com/huyi2006/articles/187777.htmlhttp://www.tkk7.com/huyi2006/comments/187777.htmlhttp://www.tkk7.com/huyi2006/articles/187777.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/187777.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/187777.html
/* Description of data base entry for a single host. */
struct hostent
{
char *h_name; /* Official name of host. */
char **h_aliases; /* Alias list. */
int h_addrtype; /* Host address type. */
int h_length; /* Length of address. */
char **h_addr_list; /* List of addresses from name server. */
#define h_addr h_addr_list[0] /* Address, for backward compatibility. */
};


struct sockaddr{
        unisgned short  as_family;
        char            sa_data[14];
};

struct sockaddr_in{
        unsigned short          sin_family;     
         unsigned short int      sin_port;
         struct in_addr          sin_addr;
         unsigned char           sin_zero[8];
}

typedef   uint32_t   in_addr_t;  
struct   in_addr   
{  
        in_addr_t   s_addr;   
};




allic 2008-03-21 19:13 发表评论
]]>
探讨C语言中的回调函数http://www.tkk7.com/huyi2006/articles/180169.htmlallicallicSat, 16 Feb 2008 04:00:00 GMThttp://www.tkk7.com/huyi2006/articles/180169.htmlhttp://www.tkk7.com/huyi2006/comments/180169.htmlhttp://www.tkk7.com/huyi2006/articles/180169.html#Feedback2http://www.tkk7.com/huyi2006/comments/commentRss/180169.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/180169.html调用者从而实现调用。回调函C用是必要的,在我们想通过一个统一接口实现?
同的内容Q这时用回掉函数非常合适。比如,我们为几个不同的讑֤分别写了不同
的显C函敎ͼvoid TVshow(); void ComputerShow(); void NoteBookShow()...{?
{。这是我们想用一个统一的显C函敎ͼ我们q时可以用回掉函数了。void sho
w(void (*ptr)()); 使用时根据所传入的参C同而调用不同的回调函数?
      不同的编E语a可能有不同的语法Q下面D一个c语言中回调函数的例子Q?
其中一个回调函C带参敎ͼ另一个回调函数带参数?
      例子1Q?
//Test.c
#include <stdlib.h>
#include <stdio.h>
int Test1()
{
  int i;
  for (i=0; i<30; i++)
  {
    printf("The %d th charactor is: %c\n", i, (char)('a' + i%26));

  }
  return 0;
}
int Test2(int num)
{
  int i;
  for (i=0; i<num; i++)
  {
   printf("The %d th charactor is: %c\n", i, (char)('a' + i%26));

  }
  return 0;
}
void Caller1(void (*ptr)())//指向函数的指针作函数参数
{
  (*ptr)();
}
void Caller2(int n, int (*ptr)())//指向函数的指针作函数参数,q里W一个参数是为指向函数的指针服务的,
{                                               //不能写成void Caller2(int (*ptr)(int n))Q这L定义语法错误?
  (*ptr)(n);
  return;
}
int main()
{
  printf("************************\n");
  Caller1(Test1); //相当于调用Test2();
  printf("&&&&&&************************\n");
  Caller2(30, Test2); //相当于调用Test2(30);
  return 0;
}
      以上通过回调函数的地址传给调用者从而实现调用,但是需要注意的是带
参回调函数的用法。要实现回调Q必首先定义函数指针。函数指针的定义q里E?
微提一下。比如:
    int (*ptr)(); q里ptr是一个函数指针,其中(*ptr)的括号不能省略,因ؓ
括号的优先高于星号Q那样就成了一个返回类型ؓ整型的函数声明了

allic 2008-02-16 12:00 发表评论
]]>
realloc,malloc,calloc的区别及free(zz)http://www.tkk7.com/huyi2006/articles/180131.htmlallicallicFri, 15 Feb 2008 14:01:00 GMThttp://www.tkk7.com/huyi2006/articles/180131.htmlhttp://www.tkk7.com/huyi2006/comments/180131.htmlhttp://www.tkk7.com/huyi2006/articles/180131.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/180131.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/180131.html

三个函数的申明分别是:
void* realloc(void* ptr, unsigned newsize);
void* malloc(unsigned size);
void* calloc(size_t nelem, size_t elsize);
都在stdlib.h函数库内

它们的返回值都是请求系l分配的地址,如果hp|p回NULL

malloc用于甌一D|的地址,参数size为需要内存空间的长度,?
char* p;
p=(char*)malloc(20);

calloc?span style="FONT-WEIGHT: bold">malloc怼,参数nelem为申请地址的单位元素长?elsize为元素个??
char* p;
p=(char*)calloc(sizeof(char),20);
q个例子与上一个效果相?br />
realloc是给一个已l分配了地址的指针重新分配空?参数ptr为原有的I间地址,newsize是重新申L地址长度
?
char* p;
p=(char*)malloc(sizeof(char)*20);
p=(char*)realloc(p,sizeof(char)*40);

注意Q这里的I间长度都是以字节ؓ单位?br />

C语言的标准内存分配函敎ͼmallocQ?a name="1">callocQreallocQfree{?br />malloc?span style="FONT-WEIGHT: bold">calloc的区别ؓ1块与n块的区别Q?br />malloc调用形式?cd*)malloc(size)Q在内存的动态存储区中分配一块长度ؓ“size”字节的q箋区域Q返回该区域的首地址?br />calloc调用形式?cd*)calloc(nQsize)Q在内存的动态存储区中分配n块长度ؓ“size”字节的q箋区域Q返回首地址?br />realloc调用形式?cd*)realloc(*ptrQsize)Q将ptr内存大小增大到size?br />free的调用Ş式ؓfree(void*ptr)Q释放ptr所指向的一块内存空间?br />C++中ؓnew/delete函数?/p>

allic 2008-02-15 22:01 发表评论
]]>
Linux C~程——线E同?/title><link>http://www.tkk7.com/huyi2006/articles/180025.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Fri, 15 Feb 2008 02:15:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/180025.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/180025.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/180025.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/180025.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/180025.html</trackback:ping><description><![CDATA[ <table style="TABLE-LAYOUT: fixed"> <tbody> <tr> <td> <div id="tp13fdh" class="cnt">使用U程~写E序需要技巧,而多U程的程序中的bug非常难以跟踪、调试,因ؓq些bugl常是难以再现的?br /><strong><br />竞争条g</strong>Q?br />当一个线E访问一个数据结构的时候,另一个线E也讉K同一个数据结构,q时出C竞争条g——两个线E(也可能是多个Q竞争对同一个资源的讉K?br />当其中一个线E处理到一部分的时候,另外的线E可能进入了对同一数据的处理,而且Z调度的原因,它运行的比前一个更快;q时Q同L处理可能出C多次?br />例如Q一个代表Q务列表的单向链表Q队列)Q一个线E从当前元素中读Z下一个Q务,q发C一个Q务不是空Q准备将此一个Q务置为NULLq执行Q务;q时Q调度得这个线E停下来Q另一个线E也从当前元素中d了下一个Q务,当然下个d仍然不是I|q个U程也将要执行下一个Q务。这P在某些不q的情况下,q个d被执行了两次?br />更ؓ不幸的情况下Q执行Q务的q程中线E被中断Q此时另一个线E释放了d的内存,那么执行中的U程会导致段错误?br />在比较“幸q”的情况下,q些事情可能从来也不发生Q但是当E序q行在负荷很高的pȝ中时Q这个bug׃凸现出来?br /><br /><strong>互斥?/strong>Q?br />Z排除竞争条g的媄响,应该使一些操作变成“原子的”——这些操作既不能分割也不能中断?br />当一个线E锁定了互斥锁后Q其他线E也要求锁定q个互斥锁的时候,׃被阻塞;直到前面的线E解除锁定后Q其他线E才可以解除d恢复q行?br />GNU/Linux保证U程在锁定互斥锁的过E中不会发生竞争条gQ只有一个线E可以锁定互斥锁Q其他线E的锁定h都会被阻塞?br /><br />创徏互斥锁(MutexQ,需要:<br />`创徏一个pthread_mutex_tcd的变量,其指针传入函数pthread_mutex_init中;该函数的W二个参数是指向一个mutex属性对象(q个对象用来指定mutex的属性)的指针。mutex对象只能初始化一ơ?br />`更简单的办法是,使用PTHREAD_MUTEX_INITIALIZER来获得默认属性的mutex对象Q?br />pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;<br /><br />使用mutexQ?br />`调用pthread_mutex_lock函数Q如果mutex对象未被锁定Q则此函数立卌回;如果已被锁定Q则此函数阻塞此U程的执行,直到mutex被解除锁定?br />`每次解除锁定后,只有一个线E可以解除阻塞恢复执行,其他调用U程都会l箋d。选定的解除阻塞的U程是不可预知的?br />`调用pthread_mutex_unlock函数Q可以解除调用线E对mutex对象的锁定。在锁定mutex的线E中Q必调用此函数以解除锁定?br /><br />mutex提供了解决竞争条件的ҎQ但是它带来了一U新的bug—?strong>死锁</strong>Q?strong>deadlock</strong>Q?br />所谓死锁,是说一个线E在{待永远不会发生的条件?br />一个简单的死锁Q一个线E锁定它自己已经锁定的mutex。这时程序的表现依赖于mutex的类型:<br />`快速排他锁Qfast mutexQ——导致死锁?br />`递归排他锁(recursive mutexQ——不D死锁。同一个线E可以安全的多次锁定同一个已锁定的mutexQ但是锁定的ơ数会被记录下来Q该U程q必调用相应次数的pthread_mutex_unlock才能真正解除对mutex的锁定?br />`错排他锁Qerror-checking mutexQ——GNU/Linux视此操作为死锁,但是寚w定的mutex调用pthread_mutex_lock函数Q函数立卌回错误码EDEADLK?br /><br />mutex的锁定函CdQ有旉要一个不dp知道mutex是否已锁定的函数Q以在发现mutex已锁的情况下d成其他工作ƈ在以后再来检查。这L函数是:<br />pthread_mutex_trylock<br />如果传入的mutex已经被其他线E锁定,那么q个函数q回错误码EBUSYQ如果未被锁定,此函C锁定mutexQƈq回0。这个函C会阻塞?/div> </td> </tr> </tbody> </table> <img src ="http://www.tkk7.com/huyi2006/aggbug/180025.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-02-15 10:15 <a href="http://www.tkk7.com/huyi2006/articles/180025.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[原]linux下调试CE序中的D错误,d@环经验?/title><link>http://www.tkk7.com/huyi2006/articles/178436.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Tue, 29 Jan 2008 16:45:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/178436.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/178436.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/178436.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/178436.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/178436.html</trackback:ping><description><![CDATA[    在linux下进行CE序Ӟ隑օ会出现这里那里的错误Q对于像D错误的调试Q对于生手可能比较麻烦,无从下手Q我惌是一个CE序员的必经的经历。一旦出现这L错误是相当棘手的。相信调试过几次L错误后再ơ遇到就能很L的解决了?br />    D错误的产生主要是由于内存操作有误,如访问的数组界Q向I地址赋|取值等。调试段错误是要借助gdb调试工具。对于那些立卛_现的错误很好调试Q如果是很时间才出现的错误,可以通过生成core文g。通过调试core文g定位错误产生的地方,而有些错误ƈ非是一D看出来。像在多U程情况下,在没有保护的情况下操作数据库时也会生段错误。一个不可重入函数在单线E下q行没有问题。可能到多线E情况下׃出现界的情c因而意识到多线E下的ƈ发机制?br />    对于d@环的调试Q也可以借助gdbQ当E序出现d@环时Q将gdb attach到程序上Q如?是主q程序出现死循环Q可以通过设断Ҏ法跟t,而对于多U程E序可以通过查看哪个U程在运行,基本上能定位错误出现的地斏V?img src ="http://www.tkk7.com/huyi2006/aggbug/178436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2008-01-30 00:45 <a href="http://www.tkk7.com/huyi2006/articles/178436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>什么是core文gQ怎么产生core文g ----from csdnhttp://www.tkk7.com/huyi2006/articles/176851.htmlallicallicMon, 21 Jan 2008 14:18:00 GMThttp://www.tkk7.com/huyi2006/articles/176851.htmlhttp://www.tkk7.com/huyi2006/comments/176851.htmlhttp://www.tkk7.com/huyi2006/articles/176851.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/176851.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/176851.html1. 前言:
有的E序可以通过~译, 但在q行时会出现Segment fault(D错?. q通常都是指针错误引v?
但这不像~译错误一样会提示到文?>? 而是没有M信息, 使得我们的调试变得困难v?

2. gdb:
有一U办法是, 我们用gdb的step, 一步一步寻?
q放在短的代码中是可行? 但要让你step一个上万行的代? 我想你会从此厌恶E序员这个名? 而把他叫做调试员.
我们q有更好的办? q就是core file.

3. ulimit:
如果惌pȝ在信号中断造成的错误时产生core文g, 我们需要在shell中按如下讄:
#讄core大小为无?br />ulimit -c unlimited
#讄文g大小为无?br />ulimit unlimited


q些需要有root权限, 在ubuntu下每ơ重新打开中断都需要重新输入上面的W一条命? 来设|core大小为无?

4. 用gdb查看core文g:
下面我们可以在发生运行时信号引v的错误时发生core dump?
发生core dump之后, 用gdbq行查看core文g的内? 以定位文件中引发core dump的行.
gdb [exec file] [core file]
?
gdb ./test test.core
在进入gdb? 用bt命o查看backtrace以检查发生程序运行到哪里, 来定位core dump的文?>?

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1669532



allic 2008-01-21 22:18 发表评论
]]>
E序实例分析-Z么会陷入d@?/title><link>http://www.tkk7.com/huyi2006/articles/170368.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Tue, 25 Dec 2007 10:18:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/170368.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/170368.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/170368.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/170368.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/170368.html</trackback:ping><description><![CDATA[ <font size="2">看似单的一D늨序如?<br /> int main()<br />{<br />   int i,j[8];<br />   for(i=0;i<=8;i++)<br />    j[i]=0;<br />   return 0;<br />} <br />    gcc~译q行会陷入死循环.  <br /> <br />    因ؓ变量 i 和数l?j[8]是保存在栈中Q默认是由高地址向低地址方向存储. 输出变量地址可以发现: i 存储位置?xbfd90dec, j[0]、j[1]...j[7]在内存的地址分别?xbfdab05c?xbfdab060,...0xbfdab078. 如下所C:<br />          高地址 <--------------------------------------->低地址<br />                           i,j[7],j[6],j[5],j[4],j[3],j[2],j[1],j[0]<br /> <br />    如果在int i,j[8]后面再定义变量int c,那么c存攑֜j[0]的往低方向的下一个地址0xbfdab058 .</font> <p> <font size="2">      现在不难理解q段E序Z么会出现d@环了。j[8]的位|就是变量i所在的位置。这样当i=8时的j[i]=0语句Q实际上是i的值置?Q然?i 又从0?循环一直下?  </font> <font size="2">如果原句改为int j[8],i; ׃会出现死循环Q而仅仅是一个段界错误.</font> </p> <p> <font size="2">另一个程?<br />#include <stdio.h><br />int main()<br />{<br />        int i;<br />        char c;<br />        for(i=0;i<5;i++)<br />        {<br />                scanf("%d",&c); <br />                printf("i=%d ",i);<br />        }<br />        printf("\n");<br />}<br />~译后运?br />[foxman@local~]#./a.out<br />0    (输入0)<br />i=0  (输出 i ?<br />1<br />i=0<br />2<br />i=0<br />3<br />i=0<br />4<br />i=0<br />...<br />q样一直@环下厅R?/font> </p> <p> <font size="2">问题在于Qc被声明ؓcharcdQ而不是intcd。当E序要求scanfd一个整数时Q应该传递给它一个指向整数的指针。而程序中scanf得到的却是一个指向字W的指针Qscanf函数q不能分辨这U情况,只能这个指向字W的指针作ؓ指向整数的指针而接受,q且在指针指向的位置存储一个整数。因为整数所占的存储I间要大于字W所占的存储I间Q所以c附近的内存会被覆?</font> </p> <p> <font size="2">׃面分析,i ?c 是由高地址C地址存储在栈中,q样在c所在位|尝试存储一?字节变量Q会占用比c高的3个字?覆盖?i 字节的低3?Q即?i L为零Q一直@环下?</font> </p> <p> <font size="2">如果每次输入Ctrl+D作ؓ字符l止W不存储int到c处,那么׃输出正常i=0..4?<br /></font> </p> <img src ="http://www.tkk7.com/huyi2006/aggbug/170368.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2007-12-25 18:18 <a href="http://www.tkk7.com/huyi2006/articles/170368.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C语言面试题大汇M微Y亚洲技术中心面试题http://www.tkk7.com/huyi2006/articles/116444.htmlallicallicThu, 10 May 2007 04:27:00 GMThttp://www.tkk7.com/huyi2006/articles/116444.htmlhttp://www.tkk7.com/huyi2006/comments/116444.htmlhttp://www.tkk7.com/huyi2006/articles/116444.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/116444.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/116444.html
  U程是指q程内的一个执行单?也是q程内的可调度实?

  与进E的区别:

  (1)调度Q线E作度和分配的基本单位,q程作ؓ拥有资源的基本单?

  (2)q发性:不仅q程之间可以q发执行Q同一个进E的多个U程之间也可q发执行

  (3)拥有资源Q进E是拥有资源的一个独立单位,U程不拥有系l资源,但可以访问隶属于q程的资?

  (4)pȝ开销Q在创徏或撤消进E时Q由于系l都要ؓ之分配和回收资源Q导致系l的开销明显大于创徏或撤消线E时的开销?
 
  2.试Ҏ

  人工试Q个人复查、抽查和会审

  机器试Q黑盒测试和白盒试

  2QHeap与stack的差别?

  Heap是堆Qstack是栈?

  Stack的空间由操作pȝ自动分配/释放QHeap上的I间手动分配/释放?

  StackI间有限QHeap是很大的自由存储?

  C中的malloc函数分配的内存空间即在堆?C++中对应的是new操作W?

  E序在编译期对变量和函数分配内存都在栈上q行,且程序运行过E中函数调用时参数的传递也在栈上进行?

  3QWindows下的内存是如何管理的Q?

  4Q介l?Net?Net的安全性?

  5Q客L如何讉K.Netlg实现Web ServiceQ?

  6QC/C++~译器中虚表是如何完成的Q?

  7Q谈谈COM的线E模型。然后讨E内/外组件的差别?

  8Q谈谈IA32下的分页机制

  页(4K)两分页模式Q大?4M)一U?

  9Q给两个变量Q如何找Z个带环单链表中是什么地方出现环的?

  一个递增一Q一个递增二,他们指向同一个接Ҏ是环出现的地方

  10Q在IA32中一共有多少U办法从用户态蟩到内核态?

  通过调用门,从ring3到ring0Q中断从ring3到ring0Q进入vm86{等

  11Q如果只惌E序有一个实例运行,不能q行两个。像winamp一P只能开一个窗口,怎样实现Q?

  用内存映或全局原子Q互斥变量)、查扄口句?.

  FindWindowQ互斥,写标志到文g或注册表,׃n内存? 

  12Q如何截取键盘的响应Q让所有的‘a’变成‘b’?

  键盘钩子SetWindowsHookEx
 
  13QApartment在COM中有什么用Qؓ什么要引入Q?
 
  14Q存储过E是什么?有什么用Q有什么优点?

  我的理解是一堆sql的集合,可以建立非常复杂的查询,~译q行Q所以运行一ơ后Q以后再q行速度比单独执行SQL快很?
 
  15QTemplate有什么特点?什么时候用Q?

  16Q谈谈Windows DNAl构的特点和优点?

  17.|络~程中设计ƈ发服务器Q用多q程 ?多线E?Q请问有什么区别?

  1Q进E:子进E是父进E的复制品。子q程获得父进E数据空间、堆和栈的复制品?

  2Q线E:相对与进E而言Q线E是一个更加接q与执行体的概念Q它可以与同q程的其他线E共享数据,但拥有自q栈空_拥有独立的执行序列?

  两者都可以提高E序的ƈ发度Q提高程序运行效率和响应旉?

  U程和进E在使用上各有优~点Q线E执行开销,但不利于资源理和保护;而进E正相反。同ӞU程适合于在SMP机器上运行,而进E则可以跨机器迁UR?


allic 2007-05-10 12:27 发表评论
]]>
C语言面试题大汇M华ؓ面试?/title><link>http://www.tkk7.com/huyi2006/articles/116428.html</link><dc:creator>allic</dc:creator><author>allic</author><pubDate>Thu, 10 May 2007 03:25:00 GMT</pubDate><guid>http://www.tkk7.com/huyi2006/articles/116428.html</guid><wfw:comment>http://www.tkk7.com/huyi2006/comments/116428.html</wfw:comment><comments>http://www.tkk7.com/huyi2006/articles/116428.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.tkk7.com/huyi2006/comments/commentRss/116428.html</wfw:commentRss><trackback:ping>http://www.tkk7.com/huyi2006/services/trackbacks/116428.html</trackback:ping><description><![CDATA[1、局部变量能否和全局变量重名Q?<br /><br />  {:能,局部会屏蔽全局。要用全局变量Q需要?::" <br /><br />  局部变量可以与全局变量同名Q在函数内引用这个变量时Q会用到同名的局部变量,而不会用到全局变量。对于有些编译器而言Q在同一个函数内可以定义多个同名的局部变量,比如在两个@环体内都定义一个同名的局部变量,而那个局部变量的作用域就在那个@环体内?<br /><br />  2、如何引用一个已l定义过的全局变量Q?<br /><br />  {:extern <br /><br />  可以用引用头文g的方式,也可以用extern关键字,如果用引用头文g方式来引用某个在头文件中声明的全局变理Q假定你那个变写错了,那么在编译期间会报错Q如果你用extern方式引用Ӟ假定你犯了同L错误Q那么在~译期间不会报错Q而在q接期间报错?<br /><br />  3、全局变量可不可以定义在可被多?C文g包含的头文g中?Z么? <br /><br />  {:可以Q在不同的C文g中以static形式来声明同名全局变量?<br /><br />  可以在不同的C文g中声明同名的全局变量Q前提是其中只能有一个C文g中对此变量赋初|此时q接不会出错 <br /><br />  4、语句for( Q? Q?有什么问题?它是什么意思? <br /><br />  {:和while(1)相同?<br /><br />  5、do……while和while……do有什么区别? <br /><br />  {:前一个@环一遍再判断Q后一个判断以后再循环 <br /><br />  6、请写出下列代码的输出内?<br /><br />  #include<stdio.h> <br />  main() <br />  { <br />   int a,b,c,d; <br />   a=10; <br />   b=a++; <br />   c=++a; <br />   d=10*a++; <br />   printf("bQcQdQ?dQ?dQ?d"QbQcQdQ? <br />   return 0; <br />  } <br /><br />  {:10Q?2Q?20 <br /><br />  7、static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别? <br /><br />  全局变量(外部变量)的说明之前再冠以static 构成了静态的全局变量。全局变量本n是静态存储方式, 静态全局变量当然也是静态存储方式?q两者在存储方式上ƈ无不同。这两者的区别虽在于非静态全局变量的作用域是整个源E序Q?当一个源E序由多个源文gl成Ӟ非静态的全局变量在各个源文g中都是有效的?而静态全局变量则限制了其作用域Q?卛_在定义该变量的源文g内有效, 在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文g内,只能源文件内的函数公用, 因此可以避免在其它源文g中引起错误?<br /><br />  从以上分析可以看出, 把局部变量改变ؓ静态变量后是改变了它的存储方式x变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域, 限制了它的用范围?<br /><br />  static函数与普通函C用域不同。仅在本文g。只在当前源文g中用的函数应该说明为内部函?static)Q内部函数应该在当前源文件中说明和定义。对于可在当前源文g以外使用的函敎ͼ应该在一个头文g中说明,要用这些函数的源文件要包含q个头文?<br /><br />  static全局变量与普通的全局变量有什么区别:static全局变量只初使化一ơ,防止在其他文件单元中被引? <br /><br />  static局部变量和普通局部变量有什么区别:static局部变量只被初始化一ơ,下一ơ依据上一ơ结果| <br /><br />  static函数与普通函数有什么区别:static函数在内存中只有一份,普通函数在每个被调用中l持一份拷?<br /><br />  8、程序的局部变量存在于Q堆栈)中,全局变量存在于(静态区 Q中Q动态申h据存在于Q?堆)中?<br /><br />  9、设有以下说明和定义Q?<br /><br />  typedef union {long i; int k[5]; char c;} DATE; <br />  struct data { int cat; DATE cow; double dog;} too; <br />  DATE max; <br /><br />  则语?printf("%d",sizeof(struct date)+sizeof(max));的执行结果是Q___52____ <br /><br />  {:DATE是一个union, 变量公用I间. 里面最大的变量cd是int[5], 占用20个字? 所以它的大是20 <br />data是一个struct, 每个变量分开占用I间. 依次为int4 + DATE20 + double8 = 32. <br />所以结果是 20 + 32 = 52. <br /><br />  当然...在某?6位编辑器? int可能?字节,那么l果?int2 + DATE10 + double8 = 20 <br /><br />  10、队列和栈有什么区别? <br />   <br />  队列先进先出Q栈后进先出 <br /><br />  11、写Z列代码的输出内容 <br /><br />  #include<stdio.h> <br />  int inc(int a) <br />  { <br />   return(++a); <br />  } <br />  int multi(int*a,int*b,int*c) <br />  { <br />   return(*c=*a**b); <br />  } <br />  typedef int(FUNC1)(int in); <br />  typedef int(FUNC2) (int*,int*,int*); <br /><br />  void show(FUNC2 fun,int arg1, int*arg2) <br />  { <br />   INCp=&inc; <br />   int temp =p(arg1); <br />   fun(&temp,&arg1, arg2); <br />   printf("%d\n",*arg2); <br />  } <br /><br />  main() <br />  { <br />   int a; <br />   show(multi,10,&a); <br />   return 0; <br />  } <br /><br />  {:110 <br /><br />  12、请扑և下面代码中的所以错?<br /><br />  说明Q以下代码是把一个字W串倒序Q如“abcd”倒序后变为“dcba?<br /><br />  1?include"string.h" <br />  2、main() <br />  3、{ <br />  4?char*src="hello,world"; <br />  5?char* dest=NULL; <br />  6?int len=strlen(src); <br />  7?dest=(char*)malloc(len); <br />  8?char* d=dest; <br />  9?char* s=src[len]; <br />  10?while(len--!=0) <br />  11?d++=s--; <br />  12?printf("%s",dest); <br />  13?return 0; <br />  14、} <br /><br />  {: <br /><br />  Ҏ1Q?<br /><br />  int main() <br />  { <br />   char* src = "hello,world"; <br />   int len = strlen(src); <br />   char* dest = (char*)malloc(len+1);//要ؓ\0分配一个空?<br />   char* d = dest; <br />   char* s = &src[len-1];//指向最后一个字W?<br />   while( len-- != 0 ) <br />   *d++=*s--; <br />   *d = 0;//N要加\0 <br />   printf("%s\n",dest); <br />   free(dest);// 使用完,应当释放I间Q以免造成内存汇泄?<br />   return 0; <br />  } <br /><img src ="http://www.tkk7.com/huyi2006/aggbug/116428.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.tkk7.com/huyi2006/" target="_blank">allic</a> 2007-05-10 11:25 <a href="http://www.tkk7.com/huyi2006/articles/116428.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> Ҏ像头~程的研I小?http://www.tkk7.com/huyi2006/articles/116035.htmlallicallicTue, 08 May 2007 12:28:00 GMThttp://www.tkk7.com/huyi2006/articles/116035.htmlhttp://www.tkk7.com/huyi2006/comments/116035.htmlhttp://www.tkk7.com/huyi2006/articles/116035.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/116035.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/116035.html**//* $Id: directshow.c,v 1.22 2005/11/12 14:12:39 fuhuizhong Exp $ */

#ifndef lint
static char vcid[] = "$Id: directshow.c,v 1.22 2005/11/12 14:12:39 fuhuizhong Exp $";
#endif /* lint */


/**//*
* 作者:傅惠?
* /modified by xiaoshao_0_0
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include "jpeglib.h"
#include <setjmp.h>
#include <SDL/SDL.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#define USB_VIDEO "/dev/video1"

SDL_Surface *screen,*img;
int cam_fd;
int width,height;
const int bpp = 24;
struct video_mmap cam_mm;
struct video_capability cam_cap;
struct video_picture cam_pic;
struct video_mbuf cam_mbuf;
struct video_window win;
char *cam_data = NULL;
int nframe;

void errexit(char *msg)
...{
fputs(msg,stderr);
exit(-1);
}

void e_sig(int signum)
...{
printf(" ERROR:signal %d ",signum);
exit(-1);
}

void setup_sighandler()
...{
signal(SIGTERM,&e_sig);
signal(SIGINT,&e_sig);
signal(SIGSEGV,&e_sig);
signal(SIGILL,&e_sig);
signal(SIGFPE,&e_sig);
}

void init_video(int w,int h,int bpp); /**//* bpp == bits per pixel, 暂时无效*/
void init_screen(int w,int h,int bpp); /**//* like above*/
void read_video(int ,int);
void show_img(char *pixels);
void window_loop();
void exchange_r_b( char * f,long size);
void compress_to_jpeg_file( FILE *outfile, char * image_buffer,int w,int h, int quality);
void save_snapshot();

void free_dev()
...{
printf("free device ");
close(cam_fd);
}

int main(int argc,char *argv[])
...{
int i;
float scale = 1.0;
if( argc == 2 ) ...{
scale = atof(argv[1]);
if(scale<0.3 || scale>1.0)
errexit("scale out of range (0.3 ~ 1.0) ");
}
width = (int)(640*scale);
height = (int)(480*scale);

atexit( &free_dev );
init_video(width,height,bpp);
init_screen(width,height,bpp);
setup_sighandler();

window_loop();

getchar();
munmap(cam_data,cam_mbuf.size);

exit(0);
}

void config_vid_pic()
...{
char *hp = getenv("HOME");
char cfpath[100];
FILE *cf;
int ret;
sprintf( cfpath,"%s/.dshow.conf",hp );
cf = fopen(cfpath,"r");
/**//* The struct video_picture consists of the following fields

brightness Picture brightness
hue Picture hue (colour only)
colour Picture colour (colour only)
contrast Picture contrast
whiteness The whiteness (greyscale only)
depth The capture depth (may need to match the frame buffer depth)
palette Reports the palette that should be used for this image

The following palettes are defined

VIDEO_PALETTE_GREY Linear intensity grey scale (255 is brightest).
VIDEO_PALETTE_HI240 The BT848 8bit colour cube.
VIDEO_PALETTE_RGB565 RGB565 packed into 16 bit words.
VIDEO_PALETTE_RGB555 RGV555 packed into 16 bit words, top bit undefined.
VIDEO_PALETTE_RGB24 RGB888 packed into 24bit words.
VIDEO_PALETTE_RGB32 RGB888 packed into the low 3 bytes of 32bit words. The top 8bits are undefined.
VIDEO_PALETTE_YUV422 Video style YUV422 - 8bits packed 4bits Y 2bits U 2bits V
VIDEO_PALETTE_YUYV Describe me
VIDEO_PALETTE_UYVY Describe me
VIDEO_PALETTE_YUV420 YUV420 capture
VIDEO_PALETTE_YUV411 YUV411 capture
VIDEO_PALETTE_RAW RAW capture (BT848)
VIDEO_PALETTE_YUV422P YUV 4:2:2 Planar
VIDEO_PALETTE_YUV411P YUV 4:1:1 Planar
*/
if (ioctl(cam_fd, VIDIOCGPICT, &cam_pic) < 0) ...{
errexit("ERROR:VIDIOCGPICT ");
}
//cam_pic.palette =VIDEO_PALETTE_RAW;
cam_pic.palette =VIDEO_PALETTE_RGB24;

if( cf==NULL ) ...{
cam_pic.brightness = 44464;
cam_pic.hue = 36000;
cam_pic.colour = 0;
cam_pic.contrast = 43312;
cam_pic.whiteness = 13312;
cam_pic.depth = 24;
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}
return;
}

fscanf(cf,"%d",&cam_pic.brightness);
fscanf(cf,"%d",&cam_pic.hue);
fscanf(cf,"%d",&cam_pic.colour);
fscanf(cf,"%d",&cam_pic.contrast);
fscanf(cf,"%d",&cam_pic.whiteness);
fclose( cf );
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}

}

void init_video(int w,int h,int bpp) /**//* bpp == bytes per pixel*/
...{
int ret;

cam_fd = open( USB_VIDEO, O_RDWR );
if( cam_fd<0 )
errexit("Can't open video device ");

ret = ioctl( cam_fd,VIDIOCGCAP,&cam_cap );
/**//* 摄像头的基本信息
struct video_capability cam_cap;
name[32] Canonical name for this interface
type Type of interface
channels Number of radio/tv channels if appropriate
audios Number of audio devices if appropriate
maxwidth Maximum capture width in pixels
maxheight Maximum capture height in pixels
minwidth Minimum capture width in pixels
minheight Minimum capture height in pixels
*/
if( ret<0 ) ...{
errexit("Can't get device information: VIDIOCGCAP ");
}

print_device_info();

/**//* The struct video_window contains the following fields.

x The X co-ordinate specified in X windows format.
y The Y co-ordinate specified in X windows format.
width The width of the image capture.
height The height of the image capture.
chromakey A host order RGB32 value for the chroma key.
flags Additional capture flags.
clips A list of clipping rectangles. (Set only)
clipcount The number of clipping rectangles. (Set only)
*/
if( ioctl(cam_fd,VIDIOCGWIN,&win)<0 ) ...{
errexit("ERROR:VIDIOCGWIN ");
}
win.x = 0;
win.y = 0;
win.width=width;
win.height=height;
if (ioctl(cam_fd, VIDIOCSWIN, &win) < 0) ...{
errexit("ERROR:VIDIOCSWIN ");
}

config_vid_pic();

ret = ioctl(cam_fd,VIDIOCGMBUF,&cam_mbuf);
/**//*
struct video_mbuf
{
int size; Total memory to map
int frames; Frames
int offsets[VIDEO_MAX_FRAME];
};
*/

/**//*struct video_buffer.
视频~存的信息读取结构,讑֮也是一Ll构。但是一般是X自己讑֮Q你只要d好了?
void *base Base physical address of the buffer
int height Height of the frame buffer
int width Width of the frame buffer
int depth Depth of the frame buffer
int bytesperline Number of bytes of memory between the start of two adjacent lines*/

if( ret<0 ) ...{
errexit("ERROR:VIDIOCGMBUF,Can't get video_mbuf ");
}
printf("Frames:%d ",cam_mbuf.frames);
nframe = cam_mbuf.frames;
cam_data = (char*)mmap(0, cam_mbuf.size, PROT_READ|PROT_WRITE,MAP_SHARED,cam_fd,0);
if( cam_data == MAP_FAILED ) ...{
errexit("ERROR:mmap ");
}
printf("Buffer size:%d Offset:%d ",cam_mbuf.size,cam_mbuf.offsets[0]);
}

void print_device_info()
...{
int type=cam_cap.type;
int i;
char type_info[14][100]=
...{
"VID_TYPE_CAPTURE Can capture to memory",
"VID_TYPE_TUNER Has a tuner of some form",
"VID_TYPE_TELETEXT Has teletext capability",
"VID_TYPE_OVERLAY Can overlay its image onto the frame buffer",
"VID_TYPE_CHROMAKEY Overlay is Chromakeyed",
"VID_TYPE_CLIPPING Overlay clipping is supported",
"VID_TYPE_FRAMERAM Overlay overwrites frame buffer memory",
"VID_TYPE_SCALES The hardware supports image scaling",
"VID_TYPE_MONOCHROME Image capture is grey scale only",
"VID_TYPE_SUBCAPTURE Capture can be of only part of the image",
"VID_TYPE_MPEG_DECODER Can decode MPEG streams",
"VID_TYPE_MPEG_ENCODER Can encode MPEG streams",
"VID_TYPE_MJPEG_DECODER Can decode MJPEG streams",
"VID_TYPE_MJPEG_ENCODER Can encode MJPEG streams",
};
printf("Device name:%s Width:%d ~ %d Height:%d ~ %d ",
cam_cap.name,
cam_cap.maxwidth, cam_cap.minwidth,
cam_cap.maxheight, cam_cap.minheight);
for(i=0;i<14;i++)
...{
if(type&(2^i))
...{ printf(type_info[i]);
printf(" ");
}
else
...{
printf("==not supported==%s",type_info[i]);
printf(" ");
}
}
}

void init_screen(int w,int h,int bpp) // like above
...{
if ( SDL_Init(SDL_INIT_AUDIO|SDL_INIT_VIDEO) < 0 ) ...{
fprintf(stderr, "无法初始化SDL: %s ", SDL_GetError());
exit(1);
}
img = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, bpp, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000);
screen = SDL_SetVideoMode(width, height, bpp, SDL_SWSURFACE);
if ( screen == NULL ) ...{
fprintf(stderr, "无法讄视频模式Q?s ", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
}

void read_video(int captrue_frame,int sync_frame)
...{
int ret;
//int frame=0; /*q个g比较关键*/
//q个地方原作者弄错了?
cam_mm.frame=captrue_frame;
/**//* struct video_mmap
{
unsigned int frame; Frame (0 - n) for double buffer
int height,width;
unsigned int format; should be VIDEO_PALETTE_*
};
*/
ret = ioctl(cam_fd,VIDIOCMCAPTURE,&cam_mm);
if( ret<0 ) ...{
errexit("ERROR: VIDIOCMCAPTURE ");
}
//cam_mm.frame=sync_frame;
ret = ioctl(cam_fd,VIDIOCSYNC,&sync_frame);
if( ret<0 ) ...{
errexit("ERROR: VIDIOCSYNC ");
}
}

void show_img(char *pixels)
...{
int row_stride = width*3;
char *pbuf = (char*)img->pixels;
int row;

/**//* for(row=0; row<height; row++) {
memcpy(pbuf, pixels, row_stride);
pbuf += img->pitch;
pixels += row_stride;
}*/
memcpy(pbuf,pixels,row_stride*height);
SDL_BlitSurface(img, NULL, screen, NULL);
SDL_UpdateRect(screen,0,0,width,height);
}

void window_loop()
...{
int ret;
SDL_Event event;
int keystat = 0;
Uint32 ticks = 0;
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,1000);
/**///////////////
cam_mm.height = height;
cam_mm.width = width;
cam_mm.frame=0;
cam_mm.format=VIDEO_PALETTE_RGB24;
ret = ioctl(cam_fd,VIDIOCMCAPTURE,&cam_mm);

if( ret<0 ) ...{
errexit("ERROR: VIDIOCMCAPTURE ");
}
//Here just start caputer frame0,it not in the loop.
/**///////////////
while ( 1 ) ...{
SDL_PollEvent(&event);
switch (event.type) ...{
case SDL_QUIT:
exit(0);
case SDL_KEYDOWN:
if( event.key.keysym.sym == SDLK_F8 && keystat == 0 )
save_snapshot();
if( event.key.keysym.sym == SDLK_F9 && keystat == 0 )
config_vid_pic();
if( event.key.keysym.sym == SDLK_UP && keystat == 0 )
increase_brightness();
if( event.key.keysym.sym == SDLK_DOWN && keystat == 0 )
decrease_birghtness();
if( event.key.keysym.sym == SDLK_LEFT && keystat== 0 )
increase_contrast();
if( event.key.keysym.sym == SDLK_RIGHT && keystat==0 )
decrease_contrast();
keystat = 1;
break;
case SDL_KEYUP:
keystat = 0;
break;
default:
break;
}
if( (SDL_GetTicks()-ticks)<30)
continue;
read_video(1,0);//captrue=1,sync=0
show_img( cam_data+cam_mbuf.offsets[0]);
read_video(0,1);//captrue=0,sync=1
show_img( cam_data+cam_mbuf.offsets[1]);
ticks = SDL_GetTicks();
}
}
void increase_brightness()
...{
int ret=0;
cam_pic.brightness+=1000;
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}
}
void decrease_birghtness()
...{
int ret=0;
cam_pic.brightness-=1000;
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}
}
void increase_contrast()
...{
int ret=0;
cam_pic.contrast+=1000;
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}
}
void decrease_contrast()
...{
int ret=0;
cam_pic.contrast-=1000;
ret = ioctl( cam_fd, VIDIOCSPICT,&cam_pic ); /**//*讄摄像头缓冲中voideo_picture信息*/
if( ret<0 ) ...{
close(cam_fd);
errexit("ERROR: VIDIOCSPICT,Can't set video_picture format ");
}
}

void compress_to_jpeg_file( FILE *outfile, char * image_buffer,int w,int h, int quality)
...{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1]; /**//* pointer to JSAMPLE row[s] */
int row_stride; /**//* physical row width in image buffer */
int image_width;
int image_height;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
jpeg_stdio_dest(&cinfo, outfile);

image_width = w;
image_height = h;
cinfo.image_width = image_width; /**//* image width and height, in pixels */
cinfo.image_height = image_height;
cinfo.input_components = 3; /**//* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /**//* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE /**//* limit to baseline-JPEG values */);
jpeg_start_compress(&cinfo, TRUE);
row_stride = image_width * 3; /**//* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height) ...{
row_pointer[0] = (JSAMPROW)& image_buffer[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}

jpeg_finish_compress(&cinfo);

jpeg_destroy_compress(&cinfo);

/**//* And we're done! */
}
void exchange_r_b( char * f,long size)
...{
char r,b;
long i;
for( i = 0; i < size ; i++)
...{
r = *f;
b = *( f + 2);
*f = b;
*(f + 2) = r;
f = f +3;
}

}

void save_snapshot()
...{
char *basepath = getenv("HOME");
char *basename = "/snapsot";
char *extname = ".jpg";
char filename[100];
int i = 0;
FILE *fo;
for(;;) ...{
sprintf(filename,"%s%s%d%s",basepath,basename,i,extname);
fo = fopen(filename,"rb");
if( fo==NULL )
break;
else
fclose(fo);
i += 1;
}
printf("snapshot:%s ",filename);
fo = fopen(filename,"wb");
exchange_r_b( cam_data, width*height );
compress_to_jpeg_file( fo, cam_data, width, height, 90 );
fclose(fo);
}

一个比较清淅的摄像头参数设|?br />

//loadVariablesNum("schlist.tx", 0);
//fscommand("fullscrean", true);
var my_cam = Camera.get();
//LAN
//Lower image quality, higher motion quality my_cam.setQuality(400000,0)
//Higher image quality, lower motion qualitymy_cam.setQuality(0,100)
//// 保最低品质ؓ 100Q无论采用多大的带宽
my_cam.setQuality(0, 100); //
my_cam.setKeyFrameInterval(15);
my_cam.setLoopback(true);
//my_cam.setMotionLevel(35, 1000);
my_cam.setMode(320, 240, 25, true);


// 捕获摄像?br />myVideo1.attachVideo(my_cam);
myVideo1.smoothing = true;
myVideo1._alpha = 100;
myVideo1._rotation = 360;
// 在舞C?myVideo1 对象的边界内昄视频?br />my_cam.onStatus = function(infoMsg) {
 if (infoMsg.code == 'Camera.Muted') {
  // 拒绝
  trace('User denies access to the camera');
 } else if (infoMsg.code == 'Camera.Unmuted') {
  // 接受
  trace('User allows access to the camera');
 }

};
//System.showSettings(3);
// 昄指定?Flash Player"讄"面板
stop(); 



allic 2007-05-08 20:28 发表评论
]]>
一个生产?消费者的模型http://www.tkk7.com/huyi2006/articles/115132.htmlallicallicThu, 03 May 2007 05:44:00 GMThttp://www.tkk7.com/huyi2006/articles/115132.htmlhttp://www.tkk7.com/huyi2006/comments/115132.htmlhttp://www.tkk7.com/huyi2006/articles/115132.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/115132.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/115132.html一个很好的多线E和互斥锁学习例E,是一个生产?消费者的模型


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <pthread.h>
#define BUFFER_SIZE 16

struct prodcons
{
   int buffer[BUFFER_SIZE];
   pthread_mutex_t lock;/*互斥?/
   int readpos, writepos;
   pthread_cond_t notempty;/*~冲区非IZ?/
   pthread_cond_t notfull;/*~冲区非满信?/
};

void init(struct prodcons *b)
{
   pthread_mutex_init(&b->lock, NULL);
   pthread_cond_init(&b->notempty, NULL);
   pthread_cond_init(&b->notfull, NULL);
   b->readpos = 0;
   b->writepos = 0;
}
void put(struct prodcons *b, int data)
{
   pthread_mutex_lock(&b->lock);//获取互斥?br />   while((b->writepos + 1) % BUFFER_SIZE == b->readpos)
   {
      printf("wait for not full\n");
      pthread_cond_wait(&b->notfull, &b->lock);//不满旉出d
   }
   b->buffer[b->writepos] = data;
   b->writepos++;
   if(b->writepos >= BUFFER_SIZE) b->writepos = 0;
   pthread_cond_signal(&b->notempty);//讄状态变?br />   pthread_mutex_unlock(&b->lock);//释放互斥?br />}

int get(struct prodcons *b)
{
   int data;
   pthread_mutex_lock(&b->lock);
   while(b->writepos == b->readpos)
   {
     printf("wait for not empty\n");
     pthread_cond_wait(&b->notempty, &b->lock);
   }
   data = b->buffer[b->readpos];
   b->readpos++;
   if(b->readpos >= BUFFER_SIZE) b->readpos = 0;
   pthread_cond_signal(&b->notfull);
   pthread_mutex_unlock(&b->lock);
   return data;
}

#define OVER (-1)
struct prodcons buffer;

void *producer(void *data)
{
   int n;
   for(n=0; n<1000; n++)
   {
      printf("put->%d\n",n);
      put(&buffer, n);
   }
   put(&buffer, OVER);
   printf("producer stopped\n");
   return NULL;
}

void *consumer(void *data)
{
   int d;
   while(1)
   {
      d = get(&buffer);
      if(d == OVER)
      break;
      printf("             %d->get\n",d);
   }
   printf("consumer stopped!\n");
   return NULL;
}
int main(void)
{
   pthread_t th_a, th_b;
   void *retval;
   init(&buffer);
   pthread_create(&th_a, NULL, producer, 0);
   pthread_create(&th_b, NULL, consumer, 0);
   pthread_join(th_a, &retval);
   pthread_join(th_b, &retval);
   return 0;
}
pthread_cond_wait函数Q是U程d在一个条件变量上Q原型ؓQ?br />extern int pthread_cond_wait(pthread_cond_t *_restrict_cond, pthread_mutex_t* _restrict_mutex)
U程解开mutex指向的锁q被条g变量conddQ线E可以被函数pthread_cond_signal和pthread_cond_broadcast唤醒?br />q有另一个函数pthread_cond_timedwait函数Q他比vpthread_cond_wait函数多一个时间参敎ͼl历l定旉後,d被解除?/p>

allic 2007-05-03 13:44 发表评论
]]>
C/C++中的日期和时?http://www.tkk7.com/huyi2006/articles/114844.htmlallicallicMon, 30 Apr 2007 10:50:00 GMThttp://www.tkk7.com/huyi2006/articles/114844.htmlhttp://www.tkk7.com/huyi2006/comments/114844.htmlhttp://www.tkk7.com/huyi2006/articles/114844.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/114844.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/114844.html

摘要Q?
本文从介l基概念入手Q探讨了在C/C++中对日期和时间操作所用到的数据结构和函数Qƈ对计时、时间的获取、时间的计算和显C格式等斚wq行了阐q。本文还通过大量的实例向你展CZtime.h头文件中声明的各U函数和数据l构的详l用方法?

关键字:
UTCQ世界标准时_QCalendar TimeQ日历时_QepochQ时间点Q,clock tickQ时钟计时单元)

1Q概?
在C/C++中,对字W串的操作有很多值得注意的问题,同样QC/C++Ҏ间的操作也有许多值得大家注意的地斏V最q,在技术群中有很多|友也多ơ问到过C++语言中对旉的操作、获取和昄{等的问题。下面,在这文章中Q笔者将主要介绍在C/C++中时间和日期的用方?

通过学习许多C/C++库,你可以有很多操作、用时间的Ҏ。但在这之前你需要了解一些“时间”和“日期”的概念Q主要有以下几个Q?
Coordinated Universal TimeQUTCQ:协调世界Ӟ又称Z界标准时_也就是大家所熟知的格林威L准时_Greenwich Mean TimeQGMTQ。比如,中国内地的时间与UTC的时差ؓ+8Q也是UTC+8。美国是UTC-5?
Calendar TimeQ日历时_是用“从一个标准时间点到此时的旉l过的秒数”来表示的时间。这个标准时间点对不同的~译器来说会有所不同Q但对一个编译系l来_q个标准旉Ҏ不变的,该编译系l中的时间对应的日历旉都通过该标准时间点来衡量,所以可以说日历旉是“相Ҏ间”,但是无论你在哪一个时区,在同一时刻对同一个标准时间点来说Q日历时间都是一L?
epochQ时间点。时间点在标准C/C++中是一个整敎ͼ它用此时的时间和标准旉点相差的U数Q即日历旉Q来表示?
clock tickQ时钟计时单元(而不把它叫做旉滴答ơ数Q,一个时钟计时单元的旉长短是由CPU控制的。一个clock tick不是CPU的一个时钟周期,而是C/C++的一个基本计时单位?

我们可以使用ANSI标准库中的time.h头文件。这个头文g中定义的旉和日期所使用的方法,无论是在l构定义Q还是命名,都具有明昄C语言风格。下面,我将说明在C/C++中怎样使用日期的时间功能?

2Q?计时
C/C++中的计时函数是clock()Q而与其相关的数据cd是clock_t。在MSDN中,查得对clock函数定义如下Q?
clock_t clock( void );
q个函数q回从“开启这个程序进E”到“程序中调用clock()函数”时之间的CPU旉计时单元Qclock tickQ数Q在MSDN中称之ؓ挂钟旉Qwal-clockQ。其中clock_t是用来保存时间的数据cdQ在time.h文g中,我们可以扑ֈ对它的定义:
#ifndef _CLOCK_T_DEFINED
typedef long clock_t;
#define _CLOCK_T_DEFINED
#endif
很明显,clock_t是一个长整Ş数。在time.h文g中,q定义了一个常量CLOCKS_PER_SECQ它用来表示一U钟会有多少个时钟计时单元,其定义如下:
#define CLOCKS_PER_SEC ((clock_t)1000)
可以看到每过千分之一U(1毫秒Q,调用clockQ)函数q回的值就?。下面D个例子,你可以用公式clock()/CLOCKS_PER_SEC来计一个进E自w的q行旉Q?
void elapsed_time()
{
printf("Elapsed time:%u secs.\n",clock()/CLOCKS_PER_SEC);
}
当然Q你也可以用clock函数来计你的机器运行一个@环或者处理其它事件到底花了多时_
#include “stdio.h?
#include “stdlib.h?
#include “time.h?
int main( void )
{
long i = 10000000L;
clock_t start, finish;
double duration;
/* 量一个事件持l的旉*/
printf( "Time to do %ld empty loops is ", i );
start = clock();
while( i-- )
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf( "%f seconds\n", duration );
system("pause");
}

在笔者的机器上,q行l果如下Q?
Time to do 10000000 empty loops is 0.03000 seconds
上面我们看到旉计时单元的长度ؓ1毫秒Q那么计时的_ֺ也ؓ1毫秒Q那么我们可不可以通过改变CLOCKS_PER_SEC的定义,通过把它定义的大一些,从而计时_ֺ更高呢?通过试Q你会发现这h不行的。在标准C/C++中,最的计时单位是一毫秒?

3Q与日期和时间相关的数据l构

在标准C/C++中,我们可通过tml构来获得日期和旉Qtml构在time.h中的定义如下Q?
#ifndef _TM_DEFINED
struct tm {
int tm_sec; /* U??取值区间ؓ[0,59] */
int tm_min; /* ?- 取值区间ؓ[0,59] */
int tm_hour; /* ?- 取值区间ؓ[0,23] */
int tm_mday; /* 一个月中的日期 - 取值区间ؓ[1,31] */
int tm_mon; /* 月䆾Q从一月开始,0代表一月) - 取值区间ؓ[0,11] */
int tm_year; /* q䆾Q其值等于实际年份减?900 */
int tm_wday; /* 星期 ?取值区间ؓ[0,6]Q其?代表星期天,1代表星期一Q以此类?*/
int tm_yday; /* 从每q的1?日开始的天数 ?取值区间ؓ[0,365]Q其?代表1?日,1代表1?日,以此cL */
int tm_isdst; /* 夏o时标识符Q实行夏令时的时候,tm_isdst为正。不实行夏o时的q候,tm_isdst?Q不了解情况Ӟtm_isdst()?/
};
#define _TM_DEFINED
#endif

ANSI C标准UC用tml构的这U时间表CZؓ分解旉(broken-down time)。而日历时_Calendar TimeQ是通过time_t数据cd来表C的Q用time_t表示的时_日历旉Q是从一个时间点Q例如:1970q?????U)到此时的U数。在time.h中,我们也可以看到time_t是一个长整型敎ͼ
#ifndef _TIME_T_DEFINED
typedef long time_t; /* 旉?*/
#define _TIME_T_DEFINED /* 避免重复定义 time_t */
#endif

大家可能会生疑问:既然time_t实际上是长整型,到未来的某一天,从一个时间点Q一般是1970q?????U)到那时的U数Q即日历旉Q超Z长整形所能表C的数的范围怎么办?对time_t数据cd的值来_它所表示的时间不能晚?038q??8?9?4?7U。ؓ了能够表C更久远的时_一些编译器厂商引入?4位甚x长的整Ş数来保存日历旉。比如微软在Visual C++中采用了__time64_t数据cd来保存日历时_q过_time64()函数来获得日历时_而不是通过使用32位字的time()函数Q,q样可以通过该数据类型保?001q?????U(不包括该旉点)之前的时间?

在time.h头文件中Q我们还可以看到一些函敎ͼ它们都是以time_t为参数类型或q回值类型的函数Q?
double difftime(time_t time1, time_t time0);
time_t mktime(struct tm * timeptr);
time_t time(time_t * timer);
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);

此外Qtime.hq提供了两种不同的函数将日历旉Q一个用time_t表示的整敎ͼ转换为我们^时看到的把年月日时分U分开昄的时间格式tmQ?

struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);

通过查阅MSDNQ我们可以知道Microsoft C/C++ 7.0中时间点的|time_t对象的|是从1899q?2?1???U到该时间点所l过的秒敎ͼ而其它各U版本的Microsoft C/C++和所有不同版本的Visual C++都是计算的从1970q?????U到该时间点所l过的秒数?

4Q与日期和时间相关的函数及应?

在本节,我将向大家展C怎样利用time.h中声明的函数Ҏ间进行操作。这些操作包括取当前旉、计时间间隔、以不同的Ş式显C时间等内容?

4.1 获得日历旉

我们可以通过time()函数来获得日历时_Calendar TimeQ,其原型ؓQtime_t time(time_t * timer);
如果你已l声明了参数timerQ你可以从参数timerq回现在的日历时_同时也可以通过q回D回现在的日历旉Q即从一个时间点Q例如:1970q?????U)到现在此时的U数。如果参CؓI(NULQ,函数只通过q回D回现在的日历旉Q比如下面这个例子用来显C当前的日历旉Q?

#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
printf("The Calendar Time now is %d\n",lt);
return 0;
}

q行的结果与当时的时间有养I我当时运行的l果是:

The Calendar Time now is 1122707619

其中1122707619是我运行程序时的日历时间。即?970q?????U到此时的秒数?

4.2 获得日期和时?

q里说的日期和时间就是我们^时所说的q、月、日、时、分、秒{信息。从W?节我们已l知道这些信息都保存在一个名为tm的结构体中,那么如何一个日历时间保存ؓ一个tml构的对象呢Q?

其中可以使用的函数是gmtime()和localtime()Q这两个函数的原型ؓQ?

struct tm * gmtime(const time_t *timer);
struct tm * localtime(const time_t * timer);

其中gmtime()函数是将日历旉转化Z界标准时_x林尼L_Qƈq回一个tml构体来保存q个旉Q而localtime()函数是将日历旉转化为本地时间。比如现在用gmtime()函数获得的世界标准时间是2005q??0??8?0U,那么我用localtime()函数在中国地得的本地旉会比世界标准旉?个小Ӟ?005q??0?5?8?0U。下面是个例子:
#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *local;
time_t t;
t=time(NUL);
local=localtime(&t);
printf("Local hour is: %d\n",local->tm_hour);
local=gmtime(&t);
printf("UTC hour is: %d\n",local->tm_hour);
return 0;
}

q行l果是:

Local hour is: 15
UTC hour is: 7

4.3 固定的时间格?

我们可以通过asctime()函数和ctime()函数时间以固定的格式显C出来,两者的q回值都是char*型的字符丌Ӏ返回的旉格式为:

星期?月䆾 日期 ??U?q\n\0
例如QWed Jan 02 02:03:55 1980\n\0

其中\n是一个换行符Q\0是一个空字符Q表C字W串l束。下面是两个函数的原型:
char * asctime(const struct tm * timeptr);
char * ctime(const time_t *timer);
其中asctime()函数是通过tml构来生成具有固定格式的保存旉信息的字W串Q而ctime()是通过日历旉来生成时间字W串。这L话,asctimeQ)函数只是把tml构对象中的各个域填到时间字W串的相应位|就行了Q而ctimeQ)函数需要先参照本地的时间设|,把日历时间{化ؓ本地旉Q然后再生成格式化后的字W串。在下面Q如果t是一个非I的time_t变量的话Q那么:
printf(ctime(&t));
{h于:
struct tm *ptr;
ptr=localtime(&t);
printf(asctime(ptr));
那么Q下面这个程序的两条printf语句输出的结果就是不同的了(除非你将本地时区设ؓ世界标准旉所在的时区Q:

#include "time.h"
#include "stdio.h"
int main(void)
{
struct tm *ptr;
time_t lt;
lt =time(NUL);
ptr=gmtime(<);
printf(asctime(ptr));
printf(ctime(<));
return 0;
}

q行l果Q?

Sat Jul 30 08:43:03 2005
Sat Jul 30 16:43:03 2005

4.4 自定义时间格?

我们可以使用strftimeQ)函数时间格式化为我们想要的格式。它的原型如下:

size_t strftime(
char *strDest,
size_t maxsize,
const char *format,
const struct tm *timeptr
);

我们可以Ҏformat指向字符串中格式命o把timeptr中保存的旉信息攑֜strDest指向的字W串中,最多向strDest中存放maxsize个字W。该函数q回向strDest指向的字W串中放|的字符数?

函数strftime()的操作有些类gsprintf()Q识别以癑ֈ?%)开始的格式命o集合Q格式化输出l果攑֜一个字W串中。格式化命o说明串strDest中各U日期和旉信息的确切表C方法。格式串中的其他字符原样放进串中。格式命令列在下面,它们是区分大写的?

%a 星期几的?
%A 星期几的全称
%b 月分的简?
%B 月䆾的全U?
%c 标准的日期的旉?
%C q䆾的后两位数字
%d 十进制表C的每月的第几天
%D ??q?
%e 在两字符域中Q十q制表示的每月的W几?
%F q???
%g q䆾的后两位数字Q用基于周的年
%G q分Q用基于周的年
%h 写的月䆾?
%H 24时制的时
%I 12时制的时
%j 十进制表C的每年的第几天
%m 十进制表C的月䆾
%M 十时制表C的分钟?
%n 新行W?
%p 本地的AM或PM的等hC?
%r 12时的时?
%R 昄时和分钟:hh:mm
%S 十进制的U数
%t 水^制表W?
%T 昄时分U:hh:mm:ss
%u 每周的第几天Q星期一为第一?Qg0?Q星期一?Q?
%U W年的第几周Q把星期日做为第一天(g0?3Q?
%V 每年的第几周Q用基于周的年
%w 十进制表C的星期几(g0?Q星期天?Q?
%W 每年的第几周Q把星期一做ؓW一天(g0?3Q?
%x 标准的日期串
%X 标准的时间串
%y 不带世纪的十q制q䆾Qg0?9Q?
%Y 带世U部分的十进制年?
%zQ?Z 时区名称Q如果不能得到时区名U则q回I字W?
%% 癑ֈ?

如果xC现在是几点了,q以12时制显C,p下面q段E序Q?

#include “time.h?
#include “stdio.h?
int main(void)
{
struct tm *ptr;
time_t lt;
char str[80];
lt=time(NUL);
ptr=localtime(<);
strftime(str,100,"It is now %I %p",ptr);
printf(str);
return 0;
}

其运行结果ؓQ?
It is now 4PM

而下面的E序则显C当前的完整日期Q?

#include <stdio.h>
#include <time.h>

void main( void )
{
struct tm *newtime;
char tmpbuf[128];
time_t lt1;
time( <1 );
newtime=localtime(<1);
strftime( tmpbuf, 128, "Today is %A, day %d of %B in the year %Y.\n", newtime);
printf(tmpbuf);
}

q行l果Q?

Today is Saturday, day 30 of July in the year 2005.

4.5 计算持箋旉的长?

有时候在实际应用中要计算一个事件持l的旉长度Q比如计打字速度。在W?节计旉分中Q我已经用clock函数举了一个例子。Clock()函数可以_到毫U。同Ӟ我们也可以用difftime()函数Q但它只能精到U。该函数的定义如下:

double difftime(time_t time1, time_t time0);

虽然该函数返回的以秒计算的时间间隔是doublecd的,但这q不说明该时间具有同double一L_度,q是由它的参数觉得的Qtime_t是以Uؓ单位计算的)。比如下面一D늨序:

#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
time_t start,end;
start = time(NUL);
system("pause");
end = time(NUL);
printf("The pause used %f seconds.\n",difftime(end,start));//<-
system("pause");
return 0;
}

q行l果为:
hL键l? . .
The pause used 2.000000 seconds.
hL键l? . .

可以惛_Q暂停的旉q不那么巧是整整2U钟。其实,你将上面E序的带有?/<-”注释的一行用下面的一行代码替换:

printf("The pause used %f seconds.\n",end-start);

其运行结果是一L?

4.6 分解旉转化为日历时?

q里说的分解旉是以年、月、日、时、分、秒{分量保存的旉l构Q在C/C++中是tml构。我们可以用mktimeQ)函数用tml构表示的时间{化ؓ日历旉。其函数原型如下Q?
time_t mktime(struct tm * timeptr);
其返回值就是{化后的日历时间。这h们就可以先制定一个分解时_然后对这个时间进行操作了Q下面的例子可以计算?997q??日是星期几:
#include "time.h"
#include "stdio.h"
#include "stdlib.h"
int main(void)
{
struct tm t;
time_t t_of_day;
t.tm_year=1997-1900;
t.tm_mon=6;
t.tm_mday=1;
t.tm_hour=0;
t.tm_min=0;
t.tm_sec=1;
t.tm_isdst=0;
t_of_day=mktime(&t);
printf(ctime(&t_of_day));
return 0;
}
q行l果Q?
Tue Jul 01 00:00:01 1997

现在注意了,有了mktime()函数Q是不是我们可以操作现在之前的Q何时间呢Q你可以通过q种办法出1945q??5h星期几吗Q答案是否定的。因个时间在1970q??日之前,所以在大多数编译器中,q样的程序虽然可以编译通过Q但q行时会异常l止?

5Qȝ

本文介绍了标准C/C++中的有关日期和时间的概念Qƈ通过各种实例讲述了这些函数和数据l构的用方法。笔者认为,和时间相关的一些概忉|相当重要的,理解q些概念是理解各U时间格式的转换的基Q更是应用这些函数和数据l构的基?img src ="http://www.tkk7.com/huyi2006/aggbug/114844.html" width = "1" height = "1" />

allic 2007-04-30 18:50 发表评论
]]>
动态二l数l的内存分配问题http://www.tkk7.com/huyi2006/articles/110592.htmlallicallicSat, 14 Apr 2007 02:01:00 GMThttp://www.tkk7.com/huyi2006/articles/110592.htmlhttp://www.tkk7.com/huyi2006/comments/110592.htmlhttp://www.tkk7.com/huyi2006/articles/110592.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/110592.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/110592.html一个关于动态二l数l分配内存的问题Q以前也有做遇见q这LQ今天在|上参考了一个可以分配Q意类型的CZQ写了一个仅分配整型的二l数l小试E序Q在VC++6.0上测试通过

int **AllocMatrix ( int iRow, int iCol )
void FreeMatrix ( int** p )

CZE序Q?/p>

 

#include  < stdio.h >
#include 
< stdlib.h >
#include 
< string .h >
//////////////////////////////////////////////////////////// //
void  FreeMatrix( int   ** p);
int **  AllocMatrix( int  iRow,  int  iCol);

int   ** AllocMatrix( int  iRow,  int  iCol)
{
    
int **  tdarray  =  NULL;
    
int *  tmparray  =  NULL;
    
int  i  =   0 ;
    
// allocate pointer array
     if ( ! (tdarray  =  ( int ** )malloc( sizeof ( char * ) * iRow)))
    
{
        printf(
" allocate iRow wrong\n " );
        exit(
1 );
    }

    
// allocate actual array space
     if ( ! (tmparray  =  ( int * )malloc( sizeof ( int ) * (iRow  *  iCol))))
    
{
        FreeMatrix(tdarray);
        printf(
" allocate iRow wrong\n " );
        exit(
1 );
    }

    
// initialize memory
    memset(tmparray,  0x00 sizeof ( int ) * (iRow  *  iCol));
    
// evaluate the pointer array
     for (i = 0 ; i < iRow; i ++ )
        tdarray[i] 
=  (tmparray  +  (i *  iCol) * sizeof ( int ));
    
return  tdarray;
}


void  FreeMatrix( int   ** p)
{
    
if (p)
    
{
        free(p[
0 ]);
        free(p);
    }

}


void  main( void )
{
    
int   ** arr  =  AllocMatrix( 2 , 2 );
    arr[
1 ][ 1 =   1 ;
    arr[
0 ][ 1 =   4 ;
    printf(
" %d, %d \n " ,arr[ 1 ][ 1 ], arr[ 0 ][ 1 ]);
    FreeMatrix(arr);
}

 



allic 2007-04-14 10:01 发表评论
]]>
C语言中动态分配数l?一l?http://www.tkk7.com/huyi2006/articles/110533.htmlallicallicFri, 13 Apr 2007 13:36:00 GMThttp://www.tkk7.com/huyi2006/articles/110533.htmlhttp://www.tkk7.com/huyi2006/comments/110533.htmlhttp://www.tkk7.com/huyi2006/articles/110533.html#Feedback0http://www.tkk7.com/huyi2006/comments/commentRss/110533.htmlhttp://www.tkk7.com/huyi2006/services/trackbacks/110533.html C语言中动态分配数l?一l?
 
    当初学Pascal的时候就惌q个问题Q如何动态的定义及用数l呢Q记得一般用数组的时候都是先指定大小的。当旉老师Q老师说是不可以的。后来又问了一位教C++的老师Q他告诉我在C++里用new可以做到Q一直不用C++Q所以也不明白。今天在逛论坛时l于扑ֈ了C语言中的用法(看原?Q?/p>

    int *a;
    int N;
    scanf("%d", &N);
    a = (int *) malloc(N * sizeof(int));
    ....
    free(a);

    q样动态分配了数组a[N]。数l的长度N可输入确定,也可用程序中的变量确定。但要注意程序结束后要用free()其释放Q否则内存会泄漏?


--------------------------------------------------------------------------------
验证一下:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int i = 0;

    int *a;
    int N;

    printf("Input array length: ");
    scanf("%d", &N);
    printf("\n");

    a = (int *) malloc(N * sizeof(int));
   
    for(i = 0; i < N; i++)
    {
        a[i] = i + 1;

        printf("%-5d", a[i]);
        if ((i + 1) % 10 == 0)
            printf("\n");
    }

    free(a);

    printf("\n");   
    return 0;
}

q行l果(VC):
=========================================================
Input array length: 100?/p>

1    2    3    4    5    6    7    8    9    10
11   12   13   14   15   16   17   18   19   20
21   22   23   24   25   26   27   28   29   30
31   32   33   34   35   36   37   38   39   40
41   42   43   44   45   46   47   48   49   50
51   52   53   54   55   56   57   58   59   60
61   62   63   64   65   66   67   68   69   70
71   72   73   74   75   76   77   78   79   80
81   82   83   84   85   86   87   88   89   90
91   92   93   94   95   96   97   98   99   100

=========================================================

 



allic 2007-04-13 21:36 发表评论
]]>
վ֩ģ壺 þҹ| Ʒ˿һҳ| A޾VƷ | һػػƵĴƬ| ޹Ʒ˾þ| þñѵӰˬˬˬ| þAVվ| պ߹ۿ| ޸ƷӰ߹ۿ| aɻ߹ۿ| Ʒ޾Ʒպѷ| ĻۺϾþò| ղһ| ޳˶| ޸Ƶ| ŷУ԰Ķ| ޾ƷƵר| ޾ƷҹƵ| ëƬѹۿ| ޾Ʒ߲| ޾ƷһۺϾԴ| һëƬ߲| һĻ| ԻȫƵַ| 3344ѲŹۿƵ| ҳվ߹ۿѸ| ߿vַ| Ƶ| Ƶѹۿ| ձһѵӰ| ѹۿĻƷ| ޻ƬëƬ߹ۿ| ӰԺһ| ˳ɫ7777߹ۿ| av볱߹ۿ| ɫͼƷ| ߹ۿ| Ļþ| vavava| ѲëƬƵ| ҹҹҹҹƵ|