本人最近在复习linux编程相关的基础知识,在这里总结下,供新入门linux的同学借鉴下
先简单提一下linux吧,linux下一切皆文件,很多东西都可以用文件的一套接口来操作,比如文件,管道,设备等。linux层序一般默认打开3个文件标准输入,标准输出,标准错误输出,对应的文件描述符分别为0,1,2.。文件的基本操作有read(),write(),open(),close()ioctl(),如果你是一个linux新手的话可能有点不明所以,看下下面的代码就知道了。
1.线程创建pthread_create() 多线程代码编译的时候要加上-pthread
#include
#include
#include
#include
void * ff()
{
printf("HHHHHHHHHHHHHHHHHHHHHHHHHHHHH\n");
pthread_exit("dfadsgagagafaggag\n");
}
void* f()
{
sleep(5);
pthread_t pp;
void *rrr;
pthread_create(&pp,NULL,ff,NULL);
pthread_join(pp,&rrr);
printf("in thread\n%s",(char *)rrr);
pthread_exit("thank you for the CPU time\n");
}
int main()
{
int ret;
void * result;
pthread_t th;
ret=pthread_create(&th,NULL,f,NULL);
sleep(1);
//pthread_exit("I am going to exit in main");
pthread_join(th,&result);
printf("can you see this\n");
printf("%s",(char *)result);
}
pthread_create第一个参数是线程属性,是二个pthread_attr_t的参数,线程属性请百度,这里只介绍最入门的东西,第一个参数是线程标识符的地址,第三个参数是线程入口,第四个参数是线程入口函数参数。如果在main线程中没有调用pthread_join或者pthread_exit,那么main线程退出后,其它线程即使没有执行完也要退出
pthread_join等待线程结束,参数自己看上面的代码理解下,可以画些不同的注释看看程序运行结果差别。pthread_exit如果是在main线程中运行等待所有线程结束,如果是在其他线程中执行,创建这个线程的线程再调用pthread_join可以得到它的退出状态,
2.信号量的使用
信号量是用来同步访问临界区使用的,当访问一个全局变量时,如果不加信号量或者锁的话,多线程编程中会出问题的。
#include
#include
#include
#include
#include
#include
sem_t sem;
void exitfun()
{
printf("exit");
}
void *f()
{
while(1)
{
char buf[40];
memset(buf,0,40);
//sem_wait(&sem);
read(0,buf,40);
if(strcmp(buf,"end\n")==0)
{
exit(0);
}
write(1,buf,40);
sem_post(&sem);
//sleep(5);
}
}
int main()
{
pthread_t pt;
atexit(exitfun);
pt=pthread_create(&pt,NULL,f,NULL);
sem_init(&sem,0,1);
while(1)
{
sem_wait(&sem);
printf("in main\n");
sleep(1);
//sem_post(&sem);
sleep(1);
}
}
信号量有几个函数以sem_开头,wait等待信号量,post释放信号量,init初始化信号量,destroy删除信号量,init中参数第一个参数是全局信号量标识,第二个是进程私有还是进程共享,0为进程私有,第三个是信号量的初始值。看下代码可以多划些注释看看执行的结果。
3.linux文件理解
如上面信号量中的代码
read(0,buf,40);
write(1,buf,40);
文件的基本操作,不仅可以适用于文件(比如a.txt文件)对于设备也适用,linux进程默认打开三个设备标准输入,标准输出,标准错误输出,对应的设备描述符为0,1,2,标注输入一般是键盘,标注输出和标准错误输出一般是显示器。
read(0,buf,40);从键盘读取40个字符到buf数组,返回实际读取的字符长度,write向显示器写40个字符,遇到'\0'停止写。
这些方法是系统调用,还可以使用库函数scanf和printf来输入输出,scanf和prointf也是调用read和write系统调用来实现的。
在/dev下有三个文件 stdin stdou sdterr,系统默认执行了open(“/dev/stdout,0666),open(“/dev/stderr,0666),open(“/dev/stdin,0666),它们的返回值fenbie 是0,1,2.,linux中很多东西都是用这套函数来操作的。
4管道
管道分为有名管道和无名管道,
先说无名管道
#include
#include
#include
#include
#include
#include
#include
#include
#include
void at_exit()
{
//printf("errno=%d\n",errno);
}
int main()
{
int fd[2];
int pid;
char buf[40];
char tembuf[40];
printf("%ld %d\n",(unsigned long)stdin,STDIN_FILENO);
atexit(at_exit);
if(pipe(fd)<0)
{
exit(-1);
}
printf("%d,%d\n",fd[0],fd[1]);
pid=fork();
int len;
if(pid==0)
{
//printf("in child,waiting to read\n");
close(fd[1]);
while(1)
{
//len=read(STDIN_FILENO,buf,30);
//printf("in child,read%d,letters,%s\n",len,buf);
len=read(fd[0],buf,30);
write(1,"in child",8);
printf("%dlen=\n",len);
write(STDOUT_FILENO,buf,len);
printf("buf=%s\n",buf);
write(fd[1],"hello world\n",12);
}
}
if(pid>0)
{
//printf("in parent,waiting to read\n");
close(fd[0]);
while(1)
{
//len=read(STDIN_FILENO,buf,30);
//printf("in parent,read%d,letters,%s\n",len,buf);
len=read(0,tembuf,40);
printf("%d\n",len);
len=write(fd[1],tembuf,len);
memset(tembuf,0,40);
printf("in parent,write %d,%s\n",len,tembuf);
}
}
}
如果你的linux电脑没有打开其他设备的话你会看到fd【0】和fd【1】的值分别为3和4,fd[1]为写端,fd[0]为读端,匿名管道是半双工的,只能一端写一端读,在写端要关闭读端,在读端要关闭写端,是为了防止编程人员使用不当造成管道读写冲突,但是好像不关闭也可以,并且我试了下好像可以两端读写。我想匿名管道的设计本身并不因该提倡两端都可以读写,否则不加保护很容易出问题的。上面代码中哟一个fork系统调用,如果不清楚请百度。
有名管道
下面有两套代码,第一套可以开一个终端,第二套可以开1到多个终端,第一个代码向管道写,后面的代码读
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
char msg[40];
char msg1[40];
int fd;
int len;
if(mkfifo("fifo",0666)<0)
{
perror("mkfifo");
printf("hhhhhhhhhhhhhhhhhh");
exit(-1);
}
fd=open("fifo",0666);
while(1)
{
len=read(0,msg,40);
printf("%s,%d\n",msg,len);
write(fd,msg,len);
printf("----------------------------\n");
//len=read(fd,msg1,40);
//printf("%s\n",msg1);
memset(msg,0,40);
}
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main()
{
char msg[40];
char msg1[40];
int fd;
int len;
fd=open("fifo",0666);
while(1)
{
len=read(fd,msg,40);
printf("%s-------------------------\n",msg);
sleep(3);
memset(msg,0,40);
}
}
创建线程后在目录下会有一个管道文件,如果不删掉,再次执行程序会直接退出,提示管道已存在。
4后续学习再,本次主要是从代码方面去理解linux这些函数。