文档库 最新最全的文档下载
当前位置:文档库 › Linux编程笔记

Linux编程笔记

Linux编程笔记
Linux编程笔记

#include //线程 -lpthread

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

2010年9月16日

C/C++复习

2010年9月17日上午

1、静态库文件与动态库文件

2、vm使用与windows相连

a、Linux设置网卡vi /etc/sysconfig/network-scripts/ifcfg-eth0,修改IP地址

b、设置虚拟网卡IP与linux中的IP在同一网段。

c、在vm中设置以太网卡为虚拟网卡连接vm机。

d、service network restart / service iptables stop / smbpasswd 改smb服务密码

就可以在windows中通过ip 访问linux服务器了。

e、改成在windows中可写linux中的文件vi /etc/samba/smb.conf 改[root]

下的writeable = yes 。添加path = / 则可以在windows中看到linux中的所有目录了。Linux 中的/,在windows中即反映为root目录下面再有root,home,etc等等。

【注】若把虚拟机也设在与主机在同一网段上(如win192.168.0.70;linux192.168.0.211)则虚拟机的网卡设置时,直接设置成[网络连接:桥接,直接连接到物理网络]。

2010年9月17日下午

Markfile

//func.c

#include

int func()

{puts("func(),haha!"); return 0;}

//main.c

#include

int func();

{func(); return 0;}

#makefile

OBJS := $(patsubst %.c,%.o,$(wildcard *.c)) #定义变量

CC := gcc #定义变量CFLAGS := -O2 #定义变量

a.out: $(OBJS) #调用变量

$(CC) $^ -o $@

#%.o:%.c

# $(CC) $(CFLAGS) -c $< -o $@

clean: #定义一个执行体$(RM) *.o *.out -rf

test:

@echo "source file list:$(patsubst %.c,%.o,$(wildcard *.c))"

.PHONY : clean test

2010年9月18日上午

讲课内容:makefile

Makefile中的变量与函数

作业:

#include

int main()

{puts("a.c"); return 0;}

#include

int main()

{puts("b.c"); return 0;}

#include

int main()

{puts("c.c"); return 0;}

写makefile 一次性编译链接三个可执行文件

a.c;

b.c;

c.c

a.out

b.out

c.out

#makefile内容如下:

OUTS := $(patsubst %.c,%.out,$(wildcard *.c))

CC := gcc

all:$(OUTS)

%.out:%.c

$(CC) $^ -o $@ -g –Wall -lpthread

clean:

$(RM) *.o *.out -rf

.PHONY : clean

2010年9月18日下午

Gdb调试工具

G++编译时,带-g –Wall (表示输出所有的警告Warning + all信息。)

Gdb a.out 或gdb 然后用file a.out.

List命令:显示源程序,eg:L 1, 从第一行开始,显示10行

L 1,20 从第一行开始,显示20行。

L a.cpp:main 显示main函数

Ptype CmyVector 看变量的类型。

Bt 显示执行到哪里了,还可以显示函数的调用关系。显示的这一行表示马上要执行的行。P m_size 打印m_size的值。P /x m_size 表示以16进制显示。

Next/step(进入函数内部):单步调试。

Finish 完成当前的函数。即跳出已经进入的函数,回到调入点。

Break(b) 72 即在72行设置断点。删除断点d 72 ; d 则是删除所有断点linux y/n时,默认为n,输入y才表示确定。在某函数处设断点b main。查看断点信息info b

Continue 让程序执行到下一个断点。

退出gdb quit(q)

作业,gdb调试以下程序

#include

using namespace std;

/*

填充该类,以便main()中的调用能正常

工作,注意,不要修改main()中的任何语句

*/

class CMyVector

{

public:

CMyVector()

{

m_pData=NULL;

m_iSize=0;

}

~CMyVector()

{

free(m_pData);

}

CMyVector(const CMyVector &src)

{

m_iSize=src.m_iSize;

m_pData=(int *)malloc(4*m_iSize);

memcpy(m_pData,src.m_pData,4*m_iSize);

}

void push_back(int data)

{

m_iSize++;

m_pData=(int *)realloc(m_pData,4*m_iSize);

m_pData[m_iSize-1]=data;

}

int size()

{

return m_iSize;

}

int operator[](int iIndex)

{

return m_pData[iIndex];

}

CMyVector &operator=(const CMyVector &src)

{

free(m_pData);

m_iSize=src.m_iSize;

m_pData=(int *)malloc(4*m_iSize);

memcpy(m_pData,src.m_pData,4*m_iSize);

return *this;

}

private:

int *m_pData;

int m_iSize;

};

int main()

{

CMyVector v;

v.push_back(2);

v.push_back(6);

v.push_back(4);

v.push_back(5);

for(int i=0; i

cout<

cout<

//上面语句应该输出"2 6 4 5 "

CMyVector v2=v;

v2.push_back(6);

for(i=0; i

cout<

cout<

//上面语句应该输出"2 6 4 5 6 "

CMyVector v3;

//i的变量要提出在这里写以兼容linux与windows.

//int i = 0;

v3=v2;

v3.push_back(0);

for(i=0; i

//scoping using obsolete binding at 'i'

//?????可以把for 看成一个小函数,另行开stock,i在{}还存在,但是在for ()里不存在了。

cout<

cout<

//上面语句应该输出"2 6 4 5 6 0 "

return 0;

}

不清楚则把每个变量还原.

2010年9月20日上午

内容,linux下文件读取方法

Open,write close 与C标准库的fopen,fwrite,fclose区别:

1\write不用关闭即写入到文件,没有缓冲区,比较低级的操作方式。Fwrite有缓冲区,所以fwrite更高效。不用总是写硬盘。所以以后要选用fwrite方式。

2\fwrite移植性好。

3\若在同一进程中,用两种方式打开不同文件(或先关闭再打开另一个),所用的文件打开表是同一个,但是在文件打开表中的文件描述符是不同的。

重要函数fileno(fp) //得到文件指针所指向的文件打开表文件描述符。

fdopen(fd,”wb”) //C标准库函数,通过文件打开表的文件描述符得到文件指针

#include

#include

#include

#include

#include

#include

int main(void)

{

char buf[] = "hello";

/* 定义文件指针,然后通过文件打开表中的文件描述符写入

FILE *fp;

fp = fopen("./file.txt","wb");

printf("fileno %d",fileno(fp));

// fclose(fp);

int fd = fileno(fp);

//int fd = open("./file.txt",O_CREAT|O_TRUNC|O_WRONLY,0666);

printf("fd %d\n",fd);

ssize_t ssize = write(fd,buf,strlen(buf));

printf("ssize_t %d\n",ssize);

close(fd);

fclose(fp);

//*/

//* 定义文件fd,再通过文件指针写入

int fd = open("./file.txt",O_CREAT|O_TRUNC|O_WRONLY,0666);

FILE *fp;

fp = fdopen(fd,"wb"); //属于c标准库

fwrite(buf,sizeof(buf),1,fp);

fflush(fp);

close(fd);

fclose(fp);

//*/

return 0;

}

注意fd总是从3开始,说明留有0,1,2给系统用的,即标准输入stdin,标准输出stdout,标准错误stderr三个文件用。

思考题。

#include

#include

#include

#include

#include

#include

int main()

{

FILE *fp;

close(1); //关闭第二个stdout

fp=fopen("a.txt","wb"); //从下开始找空闲的文件描述符,1

puts("hello,linux!");

fflush(stdout);

fclose(fp);

return 0;

}

2010年9月21日上午(下午无课)

讲课内容:

fork与exec

parent.out

int main()

{

int fd = open("./a.txt",O_WRONLY|O_CREAT,0666);//在这里打开.

char ff[100] = '0';

strcpy(ff,"fd=");

char *fdfd;

itoa(fd,ff,10);

strcat(ff,fdfd);

char *env[] = {

ff,

NULL};

puts(ff);

execle("./child.out",NULL,env);

puts("error!");

//*/

return 0;

}

Child.out

#include "h.h"

int main(int argc,char args[])

{

//int fd;

char buf[] = "abcd";

write(3,buf,strlen(buf));//在这里写入.

close(3);

return 0;

}

留练习:

1\验证父进程中打开的文件描述符,是否可以在子进程中使用. (可以) 2\先fork建子进程,再在子进程中加载进程.

2010年9月22日上午

内容:第一种进程间通信方式,内存中建立管道(无名管道)

关闭掉所有的连接,则此管道在内存中消失.

1\

2\ 代码

int main()

{

int i = 0;

if( fork() > 0)

{

i = 1;

}else{

sleep(1);

printf(i);

} //结果输出i为0;

return 0;

}

说明父子进程代码虽混在一起,但通信并不容易,父子进程都有i ,地址都一样(但映射到不同的物理内存区域),但仍各用各的,互不干扰.

3\进程间通信方式一,无名管道

3.1\验证同一进程中的管道,写端与读端关闭情况.

关闭读端写,则会导至程序崩溃.先关闭写端读,则反回0,表示已经读到末尾或文件关闭.

3.2\验证共享管道

int main()

{

int fdPipe[2];

pipe(fdPipe);

char *szbuf;// = "abcd"; //赋值了就拷贝到了子进制,在这里赋值就是父子进程共享了初始值.

if ( fork() == 0 )

{

//child进程,读

//read(fdPipe[0],szbuf,sizeof(szbuf));

//如果不读,则输入szbuf为空.所以,必须

通过管道通信.

printf("child,szbuf:%s\n",szbuf);

}

else

{

//parent进程,写

write(fdPipe[1],szbuf,sizeof(szbuf));

char *szbuf = "abcd"; //在这里赋值则子进程不会被复制过去

printf("parent,szbuf:%s\n",szbuf);

}

return 0;

}

3.3\popen函数,思考,写一个MyOpen

popen函数功能演示:

parent.out

int main()

{

FILE *pfp = popen("./child.out","wb");

fputs("aaa",pfp);

fputs("bbb",pfp);

fputs("ccc",pfp);

fclose(pfp);

return 0;

}

Child.out

int main(int argc,char args[])

{ int i = 0

for (i = 0; i< argc, ++i)

printf(“child.out,%s”,args[i]);

}

return 0;

--------------------------------------------------------------------- MyPopen(const char *command,const char *type)

//自己实现popen.

Parent.out

#include"h.h"

#include

//步骤1创建管道,2复制进程,3改管道的为stdio,4加载进程,要返回文件指针FILE * MyPopen(const char *command,const char *type)

{

int fdPipe[2];

pipe(fdPipe);

FILE *fp;

if (fork() == 0)

{ //子进程完全复制父进程的管道信息.

close(0); //关闭子进程端管道的标准输入端

dup(fdPipe[0]); //改管道的读端为标准输入端,即stdin现在为管

道的读端. 相当于dup2(fdPipe[0]),0)

close(fdPipe[1]); //关于子进程的管道写入端

//注:加载进程后,文件打开表是可以存下来的.

execlp(command,command,NULL);

//加载进程至子进程.子进程全面由child.out接管}else{

close(fdPipe[0]); //关闭读端

fp = fdopen(fdPipe[1],type);

//把写端返回成文件指针.注type需要“wb.

}

return fp;

}

int main()

{

FILE *pfp = MyPopen("./child.out","wb");

fputs("aaa",pfp);

fputs("bbb",pfp);

fclose(pfp);

return 0;

}

Child.out

#include"h.h"

int main(int argc,const char args[])

{

char buf[100];

fgets(buf,sizeof(buf),stdin);//stdin也即是fdPipe[0],但不可以直接

用这个变量.因为子进程中加载进程后,不存在这个了.不能直接使用0(为什么?) printf("child.out,szbuf:%s",buf);

}

2010年9月22日下午

内容:讲另外两种进程间通信方式

第二种进程间通信方式(命名管道,有名管道)

建立永久的管道,命名管道,用于进程间数据共享.

重要命令mkfifo myPipe #创立在磁盘上的管道.

第三种进程间通信方式(共享内存)

共享内存段

重要函数,mmap,munmap

dd if=/dev/zero of=./data.bin bs=1024 count =1 #生成一个1kb的文件,内容全是0.

a.out与

b.out通过data.bin共享数据.

a.out

int main(int argc, char *argv[])

{

sleep(3);

char *pchData;

int fd = open("./data.bin",O_RDWR);

pchData = (char

*)mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

//strcpy(pchData,"abcd");

memset(pchData,'a',10);

printf("pchData = %s\n",pchData);

munmap(NULL,1024);

close(fd);

return 0;

}

b.out

int main()

{

int fd = open("./data.bin",O_RDWR); //两者要对应。

char *pchData = ( char

*)mmap(NULL,1024,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);

while(*pchData ==0)

sleep(1);

printf("有人改了共享文件%s\n" , pchData);

munmap(NULL,1024);

close(fd);

return 0;

}

查错方法:可以到处加puts(”xxx”),语句.,这样的好处是,可以折半找错,不用通遍找.

2010年9月23日上午

第四种进程间通信方式(消息队列)

重要函数:

int msgget(key_t key, int msgflg); //在进程中取得一个消息队列,若取同一消息队列,

//则根据key_t key的值来指定.

int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);

ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg); 函数参数说明:

int msqid:通过msgget得到的消息队列标识.即key_t key

struct msgbuf *msgp:接收数据和发送数据,都必须有以下这样的结构体来装数据.

struct msgbuf {

long mtype; /* message type, must be > 0 */

char mtext[1]; /* message data */

}; //注:在api中char mtext[1]通常表示这个成员是可以扩充的.

size_t msgsz, 数据包的大小,指承载数据的大小,即消息结构体大小减掉sizeof(long mtype) long msgtyp, 消息类型.发送接收中,可以通过这个区别接收消息.

int msgflg,消息类型.一般置0表示根据消息类型按先后次序发送接收, IPC_NOWAIT, MSG_EXCEPT, MSG_NOERROR(read the first message on the queue with message type that differs from msgtyp.)

消息队列与管道的区别:

1\消息队列可以区别消息类型,通过long mtype标识.

2\管道使用数据流,流可以多次发送,一次接收,可以组合接收.消息队列则使用数据包,必须发一次接收一次,一一发送接收.

代码:

a.out(send)

#include"h.h"

struct u_info{

char *data;

};

struct msgbufa{

long mtype;

struct u_info uifo;

};

int main(int argc, char *argv[])

{

int iRet;

int iMsg = msgget(123,IPC_CREAT|0666);

struct msgbufa package = {2,{"aaaaaaaaaa"}};//实例化结构体

iRet = msgsnd(iMsg,&package,sizeof(package)-4,0);

if ( iRet == -1)

perror("没有发送成功!"); // perror打印一些系统调用的错误信息printf("%d,%d",iMsg,iRet);

return 0;

}

b.out(recive)

#include"h.h"

struct u_info{

char *data1;

}data;

struct msgbuff{

long mtype;

struct u_info data;

};

int main()

{

//取得一个消息队列

ssize_t ssize;

struct msgbuff package;

int iMsg = msgget(123,IPC_CREAT|0666);

//从消息队列里接收数据

ssize = msgrcv(iMsg,&package,sizeof(package)-4,2,0);

printf("接收到%d",ssize);

printf("msgrcv=%s",package.data.data1);

return 0;

}

练习:

写一程序,不断增长数字写入a.txt,并且可以随时接收shell输入字符,保存到a.txt. int main(int argc, char *argv[])

{

int i = 0;

FILE *fp = fopen("./a.txt","ab");

if ( fork() == 0) //子进程

{

while(1)

{

fprintf(fp,"%d\n",i);

sleep(1);

i++;

fflush(fp);

}

fclose(fp);

}

else

{ //父进程

char buf[40];

while(1)

{

fgets(buf,40,stdin);

fputs(buf,fp);

fflush(fp);

}

fclose(fp);

}

return 0;

//以上程序可以改为fd的方式写.功能一样.

#include"h.h"

//fd怎样写二进制?.

int main(int argc, char *argv[])

{

int i = 0;

int fd = open("./a.txt",O_CREAT|O_RDWR,0666);

if ( fork() == 0) //子进程

{

char buf[40];

while(1)

{

sprintf(buf,"%d",i);

strcat(buf,"\n\0");

write(fd,buf,strlen(buf));

sleep(1);

i++;

}

close(fd);

}

else//父进程

{

char buf[40];//= {'\0'};

while(1)

{

memset(buf,0,40); //

read(0,buf,40);

//strcat(buf,"\0"); //回车就是换行,所以,只要加\0就行了.

write(fd,buf,strlen(buf));

}

close(fd);

}

return 0;

}

//问题是写进去的怎么会是二进制的?

2010年9月23日下午

第一部分:并发处理,线程:

把上午的程序改成多线程处理.

#include"h.h"

//多线程,全局变量共享.一个改了,另一个也就改了.

//多进程中,各改各的,互不干涉.但可以通过创建进程前的变量赋值实现数据初始值共享。

int i = 0;

FILE *fp = fopen("./a.txt","ab");

void * mt(void *arg) //线程所执行的函数,

//必须是这个格式(返回值void *,参数void *){

while(1){

fprintf(fp,"%d\n",i);

sleep(1);

i++;

fflush(fp);

}

}

int main(int argc, char *argv[])

{

char buf[40];

//创建另一线程,执行生成连续数

pthread_t t1;

int iRet = pthread_create(&t1,NULL,mt,NULL);

if (iRet != 0 )

perror("创建线程失败!");

while(1)

{

fgets(buf,40,stdin);

fputs(buf,fp);

fflush(fp);

}

fclose(fp);

return 0;

}

第二部分:多线程的其他情况讲解:

重要函数:

pthread_join:主线程等子线程执行完毕,清理完成资源,并返回值pthread_detach:分离子线程,让其自生自灭.自行清理自己的资源pthread_self() 得到本线程的id.

以及传结构体去子线程.

代码:

#include"h.h"

struct INFO{

int iId;

char szName[8];

};

void * ThreadFun(void * arg)

{

/*

struct INFO *pInfo = (struct INFO *)arg;

printf("%d,%s\n",pInfo->iId,pInfo->szName); //加\n有区别,为什么?

free(pInfo);

//*/

printf("%d,%s",((struct INFO *)arg)->iId,((struct INFO

*)arg)->szName); //这样也可以,但必须强制转换后再->用成员.

//free(arg); //与下一句区别? 答案,一样的,free要求的就是传入void 型的指针。

free((struct INFO *)arg);

return NULL;

}

pthread_t Test()

{

pthread_t t1;

struct INFO *pInfo = (struct INFO *)malloc(sizeof (struct INFO));

pInfo->iId = 1;

strcpy(pInfo->szName, "aaaa");

pthread_create(&t1,NULL,ThreadFun,pInfo);

//sleep(2);

return t1;

}

int main()//主线程

{

pthread_t tid = Test();

//传结构体进去,有三种方式

//1,传栈指针,在主调函数中sleep(1),再让主调函数退栈,以防内存已经修改//2,把结构体定义在全局区,子线程直接存取。

//3,把结构体开在堆上,各线程共享堆上的内存。

pthread_join(tid,NULL);//合并线程

//等待子线程执行完毕,因为主线程结束,会导致整个进程结束,清除所有的资源,还没有执行完毕的线程则会直接被清除掉了。

//但是把多条执行线路合并,虽然可以把子线程执行完毕,所分资源全部清空。但容易把并发逻辑搞成串行逻辑。

//若不用pthread_join收回线程资源,则又会形成线程资源收不回。若原线程不需要从这些线程得到任何返回数据,并且让它们

//自动清除所分资源,则可以让他分离出去,独立 (唯一的作用就是自动清理资源)

pthread_detach(tid); //主线程长期运行的情况,若子线程执行时间长的

话,则用pthread_join

printf("pthread_self = %d",pthread_self());//打印线程的ID return 0;

}

注:一般来说,不得已才用多进程与多线程,若可以用一个线程,一个进程解决的问题,则用一个线程,一个进程的方式效率会更高.

2010年9月24日上午

]

重要函数

#include

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//定义一把锁,声明+初始化

相当于以下两条语句.

pthread_mutex_t mutex;//声明

int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);

//初始化restrict这个关键可以当它不存在.表示编译器不对它进行优化的变量.

int pthread_mutex_lock(pthread_mutex_t *mutex); //等待互斥锁解开然后再锁住互斥量.

int pthread_mutex_trylock(pthread_mutex_t *mutex);//不知道干什么用的?

int pthread_mutex_unlock(pthread_mutex_t *mutex);//给互斥量解锁

int pthread_mutex_destroy(pthread_mutex_t *mutex);//销毁锁

代码:

#include"h.h"

int j = 0; //全局区里的变量,线程都可以访问.

pthread_mutex_t mutex; //声明一个锁

void *ThreadFunc(void *arg)

{

//static int i = 0 ,j = 0 ;

int i = 0;//j = 0;

for ( i = 0; i<1000000; i++)

pthread_mutex_lock(&mutex); //加锁

j++; //不加锁,则有可能同时写,所以数据有可能是随机的,乱的.

pthread_mutex_unlock(&mutex); //解锁

printf("j:%d\n",j);

return NULL;

}

int main()

{

pthread_t tid1,tid2;

pthread_mutex_init(&mutex,NULL); //初始化锁

pthread_create(&tid1,NULL,ThreadFunc,NULL);

pthread_create(&tid2,NULL,ThreadFunc,NULL);

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

pthread_mutex_destroy(&mutex); //销毁锁

printf("j=%d\n",j);

return 0;

}

----------------- 另一种示例,写文件----------------

pthread_mutex_t lock;

FILE *fp=NULL;

void *fun(void *arg)

{

char buf1[]="hello,my name is ";

char buf2[]="hanjinwei";

pthread_mutex_lock(&lock); //不加此锁则写文件乱的.

//内容无顺序,两线程抢着写.

fputs(buf1,fp);

sleep(1);

fputs(buf2,fp);

pthread_mutex_unlock(&lock);

return NULL;

}

int main()

{

pthread_t tid1,tid2;

fp=fopen("a.txt","wb");

pthread_mutex_init(&lock,NULL);

pthread_create(&tid1,NULL,fun,NULL);

pthread_create(&tid2,NULL,fun,NULL);

printf("the new thread1 id is %u\n",tid1);

printf("the new thread2 id is %u\n",tid2);

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

fclose(fp);

pthread_mutex_destroy(&lock);

return 0;

}

解决方法之二,信号量实现互斥锁:

重要函数

#include

int sem_init(sem_t *sem, int pshared, unsigned value);//实始化信号量

int sem_trywait(sem_t *sem);//不知道干什么的?

int sem_wait(sem_t *sem);//减1.

If the semaphore value is currently zero, then the calling thread shall not return

from the call to sem_wait() until it either locks the semaphore or the call is interrupted by a signal. 如果当前信号灯的值为0,则其他线程不可以进来保护的代码段执行,直到执行完毕后,由sem_post恢复(+1),让出位置,其他线程才可以进来执行.,进来一个线程减1.

int sem_post(sem_t *sem);

sem_post执行完一个线程,在这里+1,即信号量的值只是简单地增加.如果本函数执行成功,sem_post()会返回0,否则,会返回-1

代码:

#include"h.h"

#include

int j = 0; //全局区里的变量,线程都可以访问.

sem_t sem; //声明

void *ThreadFunc(void *arg)

{

//static int i = 0 ,j = 0 ;

int i = 0;//j = 0;

for ( i = 0; i<100000; i++)

{

sem_wait(&sem); // -1 此处=0时,则不充许有线程进来执行.

j++; //通过设定实始化信号量为,只充许在同一时间一个线程进来,则有可能同时写,所以数据有可能是随机的,乱的.

sem_post(&sem); // +1

}

printf("j:%d\n",j);

return NULL;

}

int main()

{

pthread_t tid1,tid2;

pthread_create(&tid1,NULL,ThreadFunc,NULL);

pthread_create(&tid2,NULL,ThreadFunc,NULL);

sem_init(&sem,0,1); //初始化//改为则同时可以二个线程进去执行,池的概念,在不是修改数据的情况下.如查询

pthread_join(tid1,NULL);

pthread_join(tid2,NULL);

//销毁

printf("最后的j=%d\n",j);

return 0;

}

第二部分:线程清理

重要函数

int pthread_cancel(pthread_t thread);//直接杀死一个线程

立即被杀,引发的问题是不会自动清理资源,必须等到本进程结束后,才得以清除.如已经打开的fd,堆上的内存等.造成浪费.

还有另一种比较温和的方式,即通过设置标志stop = 0 输入kill即stop = 1即退出.while(! = stop)

代码如下:

#include"h.h"

int stop = 0;

void *ThreadFunc(void *arg)

{

int i = 0;

while(!stop)

{

FILE *fp=fopen("./a.txt","ab");

fprintf(fp,"%d\n",i++);

fclose(fp);

sleep(2);

}

return NULL;

}

int main()

{

pthread_t tid;

char szBuf[32];

FILE *fp;

pthread_create(&tid,NULL,ThreadFunc,NULL);

while( fgets( szBuf,sizeof(szBuf),stdin) )

{

if(strstr(szBuf,"kill"))

相关文档