我们知道 一个进程内的所有线程继承其数据与环境变量,共享数据空间,但是有时候我们需要有的线程拥有独属于其自己的数据变量,让其只在某个线程内有效,比如最常见的errno,每个线程出错的原因大不相同。 这个时候就需要创建线程的私有数据(TSD)了 线程的私有数据可以被其他函数访问,但拒绝被其他线程屏蔽 TSD采用了一键多值的技术,即一个键对应多个不同的值,每个线程访问数据时通过访问该键来得到对应的数据,在不同的线程中它对应了不同的值 其实系统为每个进程维护了一个称之为Key结构的结构数组,如下图所示: (这里不介绍析构函数,图片来源网络) 如图,这个pthread_key_t(其实是unsigned int)类型的key,在进程中创建,一般为0~127 在上图中Key 结构的“标志”指示这个数据元素是否正在使用。在刚开始时所有的标志初始化为“不在使用”。当一个线程调用pthread_key_create创建一个新的线程特定数据元素时,系统会搜索Key结构数组,找出第一 继续阅读 >>


吕子健 17/08/05 09:40:01
(图片来源网络) 从图中可以看出,_exit 函数的作用是:直接使进程停止运行,清除其使用的内存空间,并清除其在内核的各种数据结构;exit 函数则在这些基础上做了一些小动作,在执行退出之前还加了若干道工序。exit() 函数与 _exit() 函数的最大区别在于exit()函数在调用exit 系统调用前要检查文件的打开情况,把文件缓冲区中的内容写回文件。也就是图中的“清理I/O缓冲”。 1> exit()和_exit()函数都是用来终止进程的。 当程序执行到exit或_exit时,系统无条件的停止剩下所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行。 2> exit()在头文件stdlib.h中声明,而_exit()声明在头文件unistd.h中声明。 exit中的参数exit_code为0代表进程正常终止,若为其他值表示程序执行过程中有错误发生。 3> exit()和_exit()的区别: a._exit()执行后立即返回给内核,而exit() 继续阅读 >>


吕子健 17/08/01 16:39:17
这一周的小项目是实现一个自己的she’ll:实现输入输出重定向,管道,支持shell的内置cd命令,支持后台运行,实现tab补全和历史记录上下翻,ctrl+c不能中断程序,设置环境变量(让其可以像bash,zsh一样运行) 各点的实现总结如下: 1.重定向:输出重定向,创建你想输出到的文件,然后用dup2(old_fd,new_fd)这个函数,将其的文件描述符置为1,因为 标准输入(stdin):代码为0 标准输出(stdout):代码为1 标准错误输出(stdeer):代码为2 所以,我们让这个我们创建的文件占据了标准输出的位置,本来要输出到屏幕上的信息就会输出到这个文件里,而输入重定向和管道思路基本相同 2.管道:管道我们将输入的数据存入文件(描述符改为0),在输出到制定文件(只要把该文件描述符置为1) 3.后台运行只要不让其父进程等待即可 4.而cd命令则是检测到有 cd 命令后在子函数或在main里用chdir函数更改当前工作目录 ***5.***ctrl+c不能中断只要我们 继续阅读 >>


吕子健 17/07/29 10:08:08
这一周的小项目是实现一个自己的she’ll:实现输入输出重定向,管道,支持shell的内置cd命令,支持后台运行,实现tab补全和历史记录上下翻,ctrl+c不能中断程序,设置环境变量(让其可以像bash,zsh一样运行) 各点的实现总结如下: 1.重定向:输出重定向,创建你想输出到的文件,然后用dup2(old_fd,new_fd)这个函数,将其的文件描述符置为1,因为 标准输入(stdin):代码为0 标准输出(stdout):代码为1 标准错误输出(stdeer):代码为2 所以,我们让这个我们创建的文件占据了标准输出的位置,本来要输出到屏幕上的信息就会输出到这个文件里,而输入重定向和管道思路基本相同 2.管道:管道我们将输入的数据存入文件(描述符改为0),在输出到制定文件(只要把该文件描述符置为1) 3.后台运行只要不让其父进程等待即可 4.而cd命令则是检测到有 cd 命令后在子函数或在main里用chdir函数更改当前工作目录 ***5.***ctrl+c不能中断只要我们 继续阅读 >>


吕子健 17/07/29 10:08:08
看书上的关于exec函数的部分有点然,百度了一下各个函数,总结如下 1.execv函数: #include <unistd.h> int exevc(const char *pathname,char *const argv[]); argv参数是一个以空指针结尾的数组,即该数组里面存放的是命令执行需要的参数,最后一个元素是NULL 并且测试过后,argv[0]里面存放什么对结果不影响,所以argv[0]应该存放的是名字,而参数在第二个及以后存放 2.execve函数 #include<unistd.h> int execve(const char * filename,char * const argv[ ],char * const envp[ ]); execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且同样需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。 该函数如果执 继续阅读 >>


吕子健 17/07/26 10:23:52
其实自己也是可以编写一个头文件的 通常都是在代码里重复多次的代码段,我们就把它编程头文件里,需要的时候直接用就好了 而在编写头文件时为防止重复定义,我们使用条件编译 下面这段代码意思就是如果没有定义MAX_H那么定义它并编译下面代码部分 头文件写好用.h扩展名保存 #ifndef _MAX_H #define _MAX_H int max( int a,int b ) { if( a > b ) return a; else return b; } #endif #include<stdio.h> #include"max.h" int main() { int a=5,b=9,t; t=max( a,b ); printf( "%d\n",t); return 0; } #include< > #include" " 的区别:尖括号编译程序会先到标准函数库中找文件 ;而引号编译程序会先从当前目录中找文件 比如上面个例子,使用尖括号就不会编译 继续阅读 >>


吕子健 17/07/24 14:23:21
今天做了一道单词逆序输出,句子顺序不变的题,输入1olleh !dlrow 2m'I morf .udh3 I ekil .mca 输出1hello world! 2I'm from hdu.3 I like acm. 想到了一个新思路,不同于以前的创建新数组保存翻转过来的单词,而是检测到空格后,直接以字符的形式挨个输出前一个单词,再单独考虑最后一个单词的输出,这样比之简单许多 上代码: #include<stdio.h> #include<string.h> int main() { int len,i,j,k,m,l,t; char str[1005]; scanf("%d",&t); getchar(); while(t--) { fgets(str,1005,stdin); l=strlen(str); str[l-1]='\0'; 继续阅读 >>


吕子健 17/07/20 21:40:54
在小组展示课设后发现了一些自己没注意到的问题,记下来,以防在日后做聊天室项目时碰到了不会犯同样的错误 总结下来主要是一些思维漏洞和代码上的BUG 1.注册账号信息时老师学生使用了同一个文件夹,这样不能区分是老师还是学生,学生注册过后能以老师的身份登录 2.在登录错误时没有返回的功能 3.在主界面选择时要求输入int类型的选项,如果输入字符串之类会崩,要解决 作者:weixin_36888577 发表于2017/7/17 17:05:02 原文链接 阅读:6 评论:0 查看评论 继续阅读 >>


吕子健 17/07/17 17:05:02
刚接触Linux的初学者对于各种命令都不知道,而纯英文的man查询又是否让你很苦恼呢,快来安装一个中文版的man手册吧 只需要简单的三步: 1.终端输入sudo apt_get install manpages_zh 2.安装后修改配置文件sudo gedit/etc/manpath.config 3.将里面所有的/usr/share/man改为/usr/share/man/zh_CN 这样就可以拥有一个中文版的man手册了,快去试试吧 注:因为很久没有更新过,所以并不全是中文 作者:weixin_36888577 发表于2017/7/15 14:58:07 原文链接 阅读:1 评论:0 查看评论 继续阅读 >>


吕子健 17/07/15 14:58:07
最近在看LinuxC这本书时,经常在代码里看见perror这个函数,并且后跟:“错误代码存入errno中,详细错误代码请参考man手册。” 查过后做一下笔记 使用perror这个函数要包含<stdlib.h>这个头文件 perror的函数原型为`void perror(const char *s)` 这个函数会先输出你传给他的实参 s 所指的字符串,后面再加上错误原因字符串。此错误原因依照全局变量errno 的值来决定要输出的字符串。 在库函数中有个errno变量,每个errno值对应着以字符串表示的错误类型。当你调用"某些"函数出错时,该函数已经重新设置了errno的值。perror函数只是将你输入的一些信息和现在的errno所对应的错误一起输出。只有当一个库函数失败时,errno才会被设置。当函数成功运行时,errno的值不会被修改。这意味着我们不能通过测试errno的值来判断是否有错误存在。反之,只有当被调用的函数提示有错误发生时检查errno的& 继续阅读 >>


吕子健 17/07/14 15:11:10