??xml version="1.0" encoding="utf-8" standalone="yes"?> 1、查询系l中安装的所有RPM?/p>
$ rpm -qa 查询当前linuxpȝ中已l安装的软g包?/p>
例:$ rpm -qa | grep -i x11 | head -3 察看pȝ中包含x11字符串的?行Y件包?/p>
2、查询Y件包是否安装 $ rpm –q rpm包名U?察看pȝ中指定Y件包是否安?/p>
? $ rpm -q bash 察看pȝ中bash软g包是否安装?/p>
"rpm -q"命o中指定的软g包名U需要准的拼写Q该命o不会在Y件包的名UCq行局部匹配的查询?/p>
3、查询已安装软g包详l信?/p>
$ rpm –qi RPM包名U?查询linuxpȝ中指定名UY件包的详l信息?/p>
例:$ rpm -qi bash 察看bash软g包的详细信息?/p>
"rpm -qi"命o的执行结果中包含较详l的信息Q包括:软g名称Q版本信息,包大,描述Q等?/p>
4、查询已安装软g包中的文件列?/p>
$ rpm –ql RPM包名U?查询已安装Y件包在当前系l中安装了哪些文件?/p>
例:$ rpm -ql bash | head -3 查看bash软g在系l中已安装文件的?行文件列表?/p>
$ rpm -ql bash | grep bin 用过滤方式察看bash中包含bin字符串的文g列表?/p>
5、查询系l中文g所属的软g?/p>
$ rpm –qf 文g名称 查询linuxpȝ中指定文件所属的软g包?/p>
例:$ rpm -qf /bin/bash 察看bash文g所属的软g包?/p>
bash-3.0-19.2 昄l果?/p>
6、查询RPM安装包文件中的信? $ rpm –qpi RPM包文件名 察看RPM包未安装前的详细信息?/p>
$ rpm –qpl RPM包文件名 察看RPM包未安装前的文g列表?/p>
"rpm -qpi和rpm -qpl q两条命令可作ؓ在安装Y件包之前对其的了解?/p>
7、rpm命o查询实例 $ which mount 获得mount命o的可执行文g路径?/p>
$ rpm –qf /bin/mount 查询/bin/mount所属的软g包?/p>
$ rpm –qi util-linux 查询/bin/mount所属Y件包的详l信息?/p>
$ rpm –qf util-linux | grep mount 查询/bin/mount所属Y件包中包括mount相关所有文件?/p>
使用rpm命o安装软g包: 1、rpm软g包地基本安装 $ rpm –i rpm安装包文件名 安装该Y件包中的文g到当前系l,安装q程不提CZQ何信息?/p>
2、在安装软g包的同时昄详细信息 $ rpm –ivh rpm安装包文?安装该Y件包中的文g到当前系l,安装q程会以癑ֈ比的形式昄安装的进度和一些其他信息?/p>
3、RPM软g包安装的依赖关系 强制安装Q? rpm --force –i rpm包文件名 注:要先满软g包的依赖关系后再q行软g包的安装Q用强制安装命令安装不能保证Y件安装到pȝ后一定能 正常q行Q因此徏议慎重用?/p>
使用rpm命o卸蝲软g包: 1、RPM软g包的卸蝲 $ rpm -e 软g包名U?/p>
软g包的卸蝲Q在卸蝲时不昄M信息?/p>
注:RPM软g包的卸蝲同样存在依赖关系Q只有在没有依赖关系存在时才能对其进行卸载?/p>
2、rpm软g包卸载的依赖关系 在用RPM命oq行卸蝲ӞRPM命o会分析要卸蝲的Y件包的依赖关p,当存在依赖关pL会自动停止,q显? 哪个软g造成的卸载失败。根据RPM提示的错误信息,定先卸载的软g包,再卸载被依赖的Y件包?/p>
使用rpm命o升软g包: $ rpm - U rpm安装包文件名 注:"rpm -u"命o中用的升软g包文件最好用RED HAT公司针对当前的linux版本官方推出的升U文Ӟ不要使用W三Ҏ供的升包?/p>
~译应用E序前的准备工作Q?/strong> 1、确认系l中已经安装了编译环?/p>
$ rpm -qa | grep gcc 定当前pȝ中安装了gcc~译器环境?/p>
2、下载prozillaE序的源代码安装包文?/p>
3、释攑ַ下蝲的源代码软g包文?/p>
$ tar jxf prozilla-2.0.4.tar.bz2 释放以下载的源代码Y件包文g到当前目录。解压后的文件名Qprozilla-2.0.4 扩展Qtar的xzvf参数用于释放以tar.gz格式的压~包?/p>
4、进入源代码目录 $ cd prozilla-2.0.4 q入目录?/p>
$ pwd 昄当前目录路径?/p>
/home/teacher/download/prozilla-2.0.4 昄l果?/p>
~译软g安装的\径: $ ./configure --prefix=/home/teacher/proz 在prozillaE序的配|中Q?--prdfix"选项可以指定应用E序~译后的安装路径Q如果不使用"--prefix" 选项指定安装路径QconfigureE序配|prozilla的默认安装\径ؓ"/usr/local/bin"目录?/p>
5、程序编译过E?/p>
$ make 使用make命oq行E序的二q制~译?/p>
6、程序安装过E?/p>
$ make install "make install"命o按照configuer命o?--prefix"选项中设定的安装路径已~译完成的应用程序安装到目标目录?/p>
7、验证编译安装的E序 $ ls /home/teacher/proz 察看proz文g夹中的文件?/p>
bin include lib man share ~译前的配置 $ ./configure - - help ~译与安装: 1、程序编译过E?/p>
$ make 2、程序安装过E?/p>
$ make install 3、验证编译安装的E序 默认模式是Command,当我们按ESC键后Q接着再输?hQ进入command模式
]]>
1、安装以rpm方式提供的Y?br>Rpm(the red hat package manager)是一个开攄软g包管理系l?br>功能Q可以安装和卸蝲RPM包的软g
#rpm –ivh *.rpm 安装RPM包;
#rpm –ivh –force *.rpm 在原先安装的基础上再安装一ơ;
#rpm –Uvh *.rpm 升rpm?br>#rpm –qa 查找列出pȝ中所有安装的rpm?br>#rpm –q sendmailQ查看sendmail包的情况
#rpm –ql sendmail:查看sendmail安装的位|?br>#rpm –e *.rpm 卸蝲rpm?br>#rpm - qlp name.rpm 查看name.rpm有哪些文?br>#rpm - qf name.rpm 查看已经装好的文件属于哪个rpm?br>#rpm2cpio filename.rpm 使用“rpm2cpio”来从RPM文档中提取文?br>
2. 安装以源代码方式提供的Y?br>Q?Q、解包解压:
#tar –xzvf *.tar.gz 解包解压后会在当前目录下建立一个子目录,如xxxx
Q?Q?cd xxxx
Q?Q?./configure
Q?Q?make
Q?Q?make install
3.Find使用范例
find . -name ls.txt
find . -name ls.txt –print
find / -name ‘c??’ –print
find / -name ‘f*’ –print
find . -name ‘f*’ –exec ls –l { } \;
find . -name f\* –ok rm { } \; Q交互式提问Q?br>find . -perm 644 –mtime 4
find . -name ‘c??’ –o -name ‘d??’
4. grep
功能Q在文g中搜d配的行ƈq行输出
语法Qgrep [参数]<要找的字?gt;<原文?gt;
-num:输出匚w行前后各num行的内容
-A num:输出匚w行后num行的内容
-B num:输出匚w行前num行的内容
-iQ忽略大写的区?br>-v:只显C出那些不包括某字串的行和文Ӟ和默认的相反
5. mkdir
功能Q创Z个目录(cMMSDOS下的md命oQ?br>语法Qmkdir [选项] dir-name
- m Ҏ建目录设|存取权限。也可以用chmod命o讄?br>- p 可以是一个\径名U。此时若路径中的某些目录不存在Q?nbsp;加上此选项后, pȝ自动徏立好那些不存在的目录,即一ơ可以徏立多个目录?br>#mkdir –m a=rwx test
#mkdir –m u=rwx,g=rx,o=rx test1
#mkdir –m 755 test2
#mkdir –p test3/test4(test3和test4均ؓ新目录)
6、rmdir
功能Q删除空目录?br>语法Qrmdir [选项] dir-name
- p 递归删除目录dirnameQ当子目录删除后其父目录为空Ӟ也一同被删除?br>7、file
功能Q查看文件类?br>语法Qfile 文g?br>
8、cat
功能Q查看文本文件的内容
语法Qcat 文g?br>9、more
功能Q分屏显C文本文件的内容?br>10、less
功能Q显C文本文件的内容Q可使用pageup和pagedown上翻下页?br>
11、head
功能Q查看文件的开头部分内?br>语法Qhead [行数] 文g?br>用法Q?head test.txt:昄?0行内?br>#head -20 test.txt 昄?0行内宏V?br>12、tail
功能Q查看文件的l尾部分内容?br>语法Qtail [行数] 文g?br>默认的行Cؓ10行?br>
13、sort
功能Q对文本文g中的各行q行排序
用法Qsort 文g?br>例:#sort 123.txt >456.txt ?23.txt排序后重定向?56.txt文g中?br>14、uniq
功能Q将重复行从输出文g中删除,只留下每条记录的唯一h
语法Q?nbsp;uniq 文g?br>#uniq 456.txt文g中的重复行删除后输出
]]>
CommandQ命令)模式Q用于输入命令;
InsertQ插入)模式Q用于插入文本;
VisualQ可视)模式Q用于视化的的高亮ƈ选定正文
:wq 强制性写入文件ƈ退出。即使文件没有被修改也强制写入,q更新文件的修改旉?br> :x 写入文gq出。仅当文件被修改时才写入Qƈ更新文g修改旉Q否则不会更新文件修Ҏ间?br> q两者一般情况下没什么不一P但是在编E方面,对编辑源文g可能会生重要媄响。因为文件即使没有修改,":wq"强制更新文g的修Ҏ_q样会让make~译整个目时以为文件被修改q了Q然后就得重新编译链接生成可执行文g。这可能会生让解的后果Q当然也产生了不必要的系l资源花销?span style="COLOR: red">?x
:w 保存Q?br> :w filename 另存为filenameQ?br> :wq! 保存退出;
:wq! filename 注:以filename为文件名保存后退出;
:q! 不保存退出;
2
]]>
/* example.c*/
#include <stdio.h>
#include <pthread.h>
void thread(void)
{
int i;
for(i=0;i<3;i++)
printf("This is a pthread.n");
}
int main(void)
{
pthread_t id;
int i,ret;
ret=pthread_create(&id,NULL,(void *) thread,NULL);
if(ret!=0){
printf ("Create pthread error!n");
exit (1);
}
for(i=0;i<3;i++)
printf("This is the main process.n");
pthread_join(id,NULL);
return (0);
}
我们~译此程序:
gcc example1.c -lpthread -o example1
q行example1Q我们得到如下结果:
This is the main process.
This is a pthread.
This is the main process.
This is the main process.
This is a pthread.
This is a pthread.
再次q行Q我们可能得到如下结果:
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.
This is a pthread.
This is the main process.
前后两次l果不一Pq是两个U程争夺CPU资源的结果。上面的CZ中,我们使用C两个函数Qpthread_create和pthread_joinQƈ声明了一个pthread_t型的变量?br>
pthread_t在头文g/usr/include/bits/pthreadtypes.h中定义:
typedef unsigned long int pthread_t;
它是一个线E的标识W。函数pthread_create用来创徏一个线E,它的原型为:
extern int pthread_create __P ((pthread_t *__thread, __const pthread_attr_t *__attr,void *(*__start_routine) (void *), void *__arg));
W一个参Cؓ指向U程标识W的指针Q第二个参数用来讄U程属性,W三个参数是U程q行函数的v始地址Q最后一个参数是q行函数的参数。这里,我们的函数thread不需要参敎ͼ所以最后一个参数设为空指针。第二个参数我们也设为空指针Q这样将生成默认属性的U程。对U程属性的讑֮和修Ҏ们将在下一节阐q。当创徏U程成功Ӟ函数q回0Q若不ؓ0则说明创建线E失败,常见的错误返回代码ؓEAGAIN和EINVAL。前者表C系l限制创建新的线E,例如U程数目q多了;后者表C第二个参数代表的线E属性值非法。创建线E成功后Q新创徏的线E则q行参数三和参数四确定的函数Q原来的U程则l运行下一行代码?
函数pthread_join用来{待一个线E的l束。函数原型ؓQ?br>
extern int pthread_join __P ((pthread_t __th, void **__thread_return));
W一个参Cؓ被等待的U程标识W,W二个参Cؓ一个用户定义的指针Q它可以用来存储被等待线E的q回倹{这个函数是一个线E阻塞的函数Q调用它的函数将一直等待到被等待的U程l束为止Q当函数q回Ӟ被等待线E的资源被收回。一个线E的l束有两U途径Q一U是象我们上面的例子一P函数l束了,调用它的U程也就l束了;另一U方式是通过函数pthread_exit来实现。它的函数原型ؓQ?br>
extern void pthread_exit __P ((void *__retval)) __attribute__ ((__noreturn__));
唯一的参数是函数的返回代码,只要pthread_join中的W二个参数thread_return不是NULLQ这个值将被传递给thread_return。最后要说明的是Q一个线E不能被多个U程{待Q否则第一个接收到信号的线E成功返回,其余调用pthread_join的线E则q回错误代码ESRCH?br>
在这一节里Q我们编写了一个最单的U程Qƈ掌握了最常用的三个函数pthread_createQpthread_join和pthread_exit。下面,我们来了解线E的一些常用属性以及如何设|这些属性?br>
修改U程的属?/strong>
在上一节的例子里,我们用pthread_create函数创徏了一个线E,在这个线E中Q我们用了默认参数Q即该函数的第二个参数设ؓNULL。的,对大多数E序来说Q用默认属性就够了Q但我们q是有必要来了解一下线E的有关属性?br>
属性结构ؓpthread_attr_tQ它同样在头文g/usr/include/pthread.h中定义,喜欢q根问底的h可以自己L看。属性g能直接设|,M用相兛_数进行操作,初始化的函数为pthread_attr_initQ这个函数必dpthread_create函数之前调用。属性对象主要包括是否绑定、是否分R堆栈地址、堆栈大、优先。默认的属性ؓ非绑定、非分离、缺?M的堆栈、与父进E同L别的优先U?br>
关于U程的绑定,牉|到另外一个概念:轻进E(LWPQLight Weight ProcessQ。轻q程可以理解为内核线E,它位于用户层和系l层之间。系l对U程资源的分配、对U程的控制是通过轻进E来实现的,一个轻q程可以控制一个或多个U程。默认状况下Q启动多轻q程、哪些轻q程来控制哪些线E是ql来控制的,q种状况即称为非l定的。绑定状况下Q则思义Q即某个U程固定?l?在一个轻q程之上。被l定的线E具有较高的响应速度Q这是因为CPU旉片的调度是面向轻q程的,l定的线E可以保证在需要的时候它L一个轻q程可用。通过讄被绑定的轻进E的优先U和调度U可以得绑定的U程满诸如实时反应之类的要求?br>
讄U程l定状态的函数为pthread_attr_setscopeQ它有两个参敎ͼW一个是指向属性结构的指针Q第二个是绑定类型,它有两个取|PTHREAD_SCOPE_SYSTEMQ绑定的Q和PTHREAD_SCOPE_PROCESSQ非l定的)。下面的代码卛_Z一个绑定的U程?
#include <pthread.h>
pthread_attr_t attr;
pthread_t tid;
/*初始化属性|均设为默认?/
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_create(&tid, &attr, (void *) my_function, NULL);
U程的分ȝ态决定一个线E以什么样的方式来l止自己。在上面的例子中Q我们采用了U程的默认属性,即ؓ非分ȝ态,q种情况下,原有的线E等待创建的U程l束。只有当pthread_joinQ)函数q回Ӟ创徏的线E才终止,才能释放自己占用的系l资源。而分ȝE不是这样子的,它没有被其他的线E所{待Q自p行结束了Q线E也q止了Q马上释攄l资源。程序员应该Ҏ自己的需要,选择适当的分ȝ态。设|线E分ȝ态的函数为pthread_attr_setdetachstateQpthread_attr_t *attr, int detachstateQ。第二个参数可选ؓPTHREAD_CREATE_DETACHEDQ分ȝE)?PTHREAD _CREATE_JOINABLEQ非分离U程Q。这里要注意的一ҎQ如果设|一个线Eؓ分离U程Q而这个线E运行又非常快,它很可能在pthread_create函数q回之前q止了Q它l止以后可能将U程号和pȝ资源UMl其他的U程使用Q这栯用pthread_create的线E就得到了错误的U程受要避免q种情况可以采取一定的同步措施Q最单的Ҏ之一是可以在被创建的U程里调用pthread_cond_timewait函数Q让q个U程{待一会儿Q留够的旉让函数pthread_createq回。设|一D늭待时_是在多线E编E里常用的方法。但是注意不要用诸如waitQ)之类的函敎ͼ它们是整个q程睡眠Qƈ不能解决U程同步的问题?br>
另外一个可能常用的属性是U程的优先Q它存放在结构sched_param中。用函数pthread_attr_getschedparam和函数pthread_attr_setschedparamq行存放Q一般说来,我们L先取优先U,对取得的g改后再存攑֛厅R下面即是一D늮单的例子?
U程的数据处?br>
#include <pthread.h>
#include <sched.h>
pthread_attr_t attr;
pthread_t tid;
sched_param param;
int newprio=20;
pthread_attr_init(&attr);
pthread_attr_getschedparam(&attr, ¶m);
param.sched_priority=newprio;
pthread_attr_setschedparam(&attr, ¶m);
pthread_create(&tid, &attr, (void *)myfunction, myarg);
和进E相比,U程的最大优点之一是数据的׃n性,各个q程׃n父进E处沿袭的数据段Q可以方便的获得、修Ҏ据。但q也l多U程~程带来了许多问题。我们必d心有多个不同的进E访问相同的变量。许多函数是不可重入的,卛_时不能运行一个函数的多个拯Q除非用不同的数据D)。在函数中声明的静态变量常常带来问题,函数的返回g会有问题。因为如果返回的是函数内部静态声明的I间的地址Q则在一个线E调用该函数得到地址后用该地址指向的数据时Q别的线E可能调用此函数q修改了q一D|据。在q程中共享的变量必须用关键字volatile来定义,q是Z防止~译器在优化Ӟ如gcc中?OX参数Q改变它们的使用方式。ؓ了保护变量,我们必须使用信号量、互斥等Ҏ来保证我们对变量的正用。下面,我们逐步介绍处理U程数据时的有关知识?br>
1、线E数?br>
在单U程的程序里Q有两种基本的数据:全局变量和局部变量。但在多U程E序里,q有W三U数据类型:U程数据QTSD: Thread-Specific DataQ。它和全局变量很象Q在U程内部Q各个函数可以象使用全局变量一栯用它Q但它对U程外部的其它线E是不可见的。这U数据的必要性是显而易见的。例如我们常见的变量errnoQ它q回标准的出错信息。它昄不能是一个局部变量,几乎每个函数都应该可以调用它Q但它又不能是一个全局变量Q否则在AU程里输出的很可能是BU程的出错信息。要实现诸如此类的变量,我们必M用线E数据。我们ؓ每个U程数据创徏一个键Q它和这个键相关联,在各个线E里Q都使用q个键来指代U程数据Q但在不同的U程里,q个键代表的数据是不同的Q在同一个线E里Q它代表同样的数据内宏V?br>
和线E数据相关的函数主要?个:创徏一个键Qؓ一个键指定U程数据Q从一个键dU程数据Q删除键?br>
创徏键的函数原型为:
extern int pthread_key_create __P ((pthread_key_t *__key,void (*__destr_function) (void *)));
W一个参Cؓ指向一个键值的指针Q第二个参数指明了一个destructor函数Q如果这个参C为空Q那么当每个U程l束Ӟpȝ调用这个函数来释放l定在这个键上的内存块。这个函数常和函数pthread_once ((pthread_once_t*once_control, void (*initroutine) (void)))一起用,Z让这个键只被创徏一ơ。函数pthread_once声明一个初始化函数Q第一ơ调用pthread_once时它执行q个函数Q以后的调用被它忽略?br>
在下面的例子中,我们创徏一个键Qƈ它和某个数据相兌。我们要定义一个函数createWindowQ这个函数定义一个图形窗口(数据cd为Fl_Window *Q这是图形界面开发工具FLTK中的数据cdQ。由于各个线E都会调用这个函敎ͼ所以我们用线E数据?br>
/* 声明一个键*/
pthread_key_t myWinKey;
/* 函数 createWindow */
void createWindow ( void ) {
Fl_Window * win;
static pthread_once_t once= PTHREAD_ONCE_INIT;
/* 调用函数createMyKeyQ创建键*/
pthread_once ( & once, createMyKey) ;
/*win指向一个新建立的窗?/
win=new Fl_Window( 0, 0, 100, 100, "MyWindow");
/* ҎH口作一些可能的讄工作Q如大小、位|、名U等*/
setWindow(win);
/* 窗口指针值绑定在键myWinKey?/
pthread_setpecific ( myWinKey, win);
}
/* 函数 createMyKeyQ创Z个键Qƈ指定了destructor */
void createMyKey ( void ) {
pthread_keycreate(&myWinKey, freeWinKey);
}
/* 函数 freeWinKeyQ释攄?/
void freeWinKey ( Fl_Window * win){
delete win;
}
q样Q在不同的线E中调用函数createMyWinQ都可以得到在线E内部均可见的窗口变量,q个变量通过函数pthread_getspecific得到。在上面的例子中Q我们已l用了函数pthread_setspecific来将U程数据和一个键l定在一赗这两个函数的原型如下:
extern int pthread_setspecific __P ((pthread_key_t __key,__const void *__pointer));
extern void *pthread_getspecific __P ((pthread_key_t __key));
q两个函数的参数意义和用方法是显而易见的。要注意的是Q用pthread_setspecificZ个键指定新的U程数据Ӟ必须自己释放原有的线E数据以回收I间。这个过E函数pthread_key_delete用来删除一个键Q这个键占用的内存将被释放,但同栯注意的是Q它只释N占用的内存,q不释放该键兌的线E数据所占用的内存资源,而且它也不会触发函数pthread_key_create中定义的destructor函数。线E数据的释放必须在释N之前完成?br>
2、互斥锁
互斥锁用来保证一D|间内只有一个线E在执行一D代码。必要性显而易见:假设各个U程向同一个文仉序写入数据,最后得到的l果一定是N性的?br>
我们先看下面一D代码。这是一个读/写程序,它们公用一个缓冲区Qƈ且我们假定一个缓冲区只能保存一条信息。即~冲区只有两个状态:有信息或没有信息?br>
void reader_function ( void );
void writer_function ( void );
char buffer;
int buffer_has_item=0;
pthread_mutex_t mutex;
struct timespec delay;
void main ( void ){
pthread_t reader;
/* 定义延迟旉*/
delay.tv_sec = 2;
delay.tv_nec = 0;
/* 用默认属性初始化一个互斥锁对象*/
pthread_mutex_init (&mutex,NULL);
pthread_create(&reader, pthread_attr_default, (void *)&reader_function), NULL);
writer_function( );
}
void writer_function (void){
while(1){
/* 锁定互斥?/
pthread_mutex_lock (&mutex);
if (buffer_has_item==0){
buffer=make_new_item( );
buffer_has_item=1;
}
/* 打开互斥?/
pthread_mutex_unlock(&mutex);
pthread_delay_np(&delay);
}
}
void reader_function(void){
while(1){
pthread_mutex_lock(&mutex);
if(buffer_has_item==1){
consume_item(buffer);
buffer_has_item=0;
}
pthread_mutex_unlock(&mutex);
pthread_delay_np(&delay);
}
}
q里声明了互斥锁变量mutexQ结构pthread_mutex_tZ公开的数据类型,其中包含一个系l分配的属性对象。函数pthread_mutex_init用来生成一个互斥锁。NULL参数表明使用默认属性。如果需要声明特定属性的互斥锁,调用函数pthread_mutexattr_init。函数pthread_mutexattr_setpshared和函数pthread_mutexattr_settype用来讄互斥锁属性。前一个函数设|属性psharedQ它有两个取|PTHREAD_PROCESS_PRIVATE和PTHREAD_PROCESS_SHARED。前者用来不同进E中的线E同步,后者用于同步本q程的不同线E。在上面的例子中Q我们用的是默认属性PTHREAD_PROCESS_ PRIVATE。后者用来设|互斥锁cdQ可选的cd有PTHREAD_MUTEX_NORMAL、PTHREAD_MUTEX_ERRORCHECK、PTHREAD_MUTEX_RECURSIVE和PTHREAD _MUTEX_DEFAULT。它们分别定义了不同的上所、解锁机Ӟ一般情况下Q选用最后一个默认属性?br>
pthread_mutex_lock声明开始用互斥锁上锁,此后的代码直臌用pthread_mutex_unlock为止Q均被上锁,卛_一旉只能被一个线E调用执行。当一个线E执行到pthread_mutex_lock处时Q如果该锁此时被另一个线E用,那此U程被阻塞,即程序将{待到另一个线E释放此互斥锁。在上面的例子中Q我们用了pthread_delay_np函数Q让U程睡眠一D|_是Z防止一个线E始l占据此函数?br>
上面的例子非常简单,׃再介l了Q需要提出的是在使用互斥锁的q程中很有可能会出现死锁Q两个线E试囑时占用两个资源,q按不同的次序锁定相应的互斥锁,例如两个U程都需要锁定互斥锁1和互斥锁2QaU程先锁定互斥锁1QbU程先锁定互斥锁2Q这时就出现了死锁。此时我们可以用函数pthread_mutex_trylockQ它是函数pthread_mutex_lock的非d版本Q当它发现死锁不可避免时Q它会返回相应的信息Q程序员可以针对死锁做出相应的处理。另外不同的互斥锁类型对死锁的处理不一P但最主要的还是要E序员自己在E序设计注意q一炏V?br>
3、条件变?br>
前一节中我们讲述了如何用互斥锁来实现线E间数据的共享和通信Q互斥锁一个明昄~点是它只有两种状态:锁定和非锁定。而条件变量通过允许U程d和等待另一个线E发送信LҎ弥补了互斥锁的不I它常和互斥锁一起用。用时Q条件变量被用来d一个线E,当条件不满ӞU程往往解开相应的互斥锁q等待条件发生变化。一旦其它的某个U程改变了条件变量,它将通知相应的条件变量唤醒一个或多个正被此条件变量阻塞的U程。这些线E将重新锁定互斥锁ƈ重新试条g是否满。一般说来,条g变量被用来进行线扉K的同步?
条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));
其中cond是一个指向结构pthread_cond_t的指针,cond_attr是一个指向结构pthread_condattr_t的指针。结构pthread_condattr_t是条件变量的属性结构,和互斥锁一h们可以用它来讄条g变量是进E内可用q是q程间可用,默认值是PTHREAD_ PROCESS_PRIVATEQ即此条件变量被同一q程内的各个U程使用。注意初始化条g变量只有未被使用时才能重新初始化或被释放。释放一个条件变量的函数为pthread_cond_ destroyQpthread_cond_t condQ。
函数pthread_cond_waitQ)使线E阻塞在一个条件变量上。它的函数原型ؓQ?br>
extern int pthread_cond_wait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex));
U程解开mutex指向的锁q被条g变量condd。线E可以被函数pthread_cond_signal和函数pthread_cond_broadcast唤醒Q但是要注意的是Q条件变量只是vd和唤醒线E的作用Q具体的判断条gq需用户l出Q例如一个变量是否ؓ0{等Q这一Ҏ们从后面的例子中可以看到。线E被唤醒后,它将重新查判断条件是否满I如果q不满Q一般说来线E应该仍d在这里,被等待被下一ơ唤醒。这个过E一般用while语句实现?br>
另一个用来阻塞线E的函数是pthread_cond_timedwaitQ)Q它的原型ؓQ?br> extern int pthread_cond_timedwait __P ((pthread_cond_t *__cond,pthread_mutex_t *__mutex, __const struct timespec *__abstime));
它比函数pthread_cond_waitQ)多了一个时间参敎ͼl历abstimeD|间后Q即使条件变量不满Q阻塞也被解除?br>
函数pthread_cond_signalQ)的原型ؓQ?br>
extern int pthread_cond_signal __P ((pthread_cond_t *__cond));
它用来释放被d在条件变量cond上的一个线E。多个线E阻塞在此条件变量上Ӟ哪一个线E被唤醒是由U程的调度策略所军_的。要注意的是Q必ȝ保护条g变量的互斥锁来保护这个函敎ͼ否则条g满信号又可能在试条g和调用pthread_cond_wait函数之间被发出,从而造成无限制的{待。下面是使用函数pthread_cond_waitQ)和函数pthread_cond_signalQ)的一个简单的例子?br>
pthread_mutex_t count_lock;
pthread_cond_t count_nonzero;
unsigned count;
decrement_count () {
pthread_mutex_lock (&count_lock);
while(count==0)
pthread_cond_wait( &count_nonzero, &count_lock);
count=count -1;
pthread_mutex_unlock (&count_lock);
}
increment_count(){
pthread_mutex_lock(&count_lock);
if(count==0)
pthread_cond_signal(&count_nonzero);
count=count+1;
pthread_mutex_unlock(&count_lock);
}
countgؓ0Ӟdecrement函数在pthread_cond_wait处被dQƈ打开互斥锁count_lock。此Ӟ当调用到函数increment_countӞpthread_cond_signalQ)函数改变条g变量Q告知decrement_countQ)停止d。读者可以试着让两个线E分别运行这两个函数Q看看会出现什么样的结果?br>
函数pthread_cond_broadcastQpthread_cond_t *condQ用来唤醒所有被d在条件变量cond上的U程。这些线E被唤醒后将再次竞争相应的互斥锁Q所以必d心用这个函数?br>
4、信号量
信号量本质上是一个非负的整数计数器,它被用来控制对公p源的讉K。当公共资源增加Ӟ调用函数sem_postQ)增加信号量。只有当信号量值大于0Ӟ才能使用公共资源Q用后Q函数sem_waitQ)减少信号量。函数sem_trywaitQ)和函数pthread_ mutex_trylockQ)起同L作用Q它是函数sem_waitQ)的非d版本。下面我们逐个介绍和信号量有关的一些函敎ͼ它们都在头文?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));
sem为指向信号量l构的一个指针;pshared不ؓQ时此信号量在进E间׃nQ否则只能ؓ当前q程的所有线E共享;valuel出了信号量的初始倹{?br>
函数sem_post( sem_t *sem )用来增加信号量的倹{当有线E阻塞在q个信号量上Ӟ调用q个函数会其中的一个线E不在阻塞,选择机制同样是由U程的调度策略决定的?br>
函数sem_wait( sem_t *sem )被用来阻塞当前线E直C号量sem的值大?Q解除阻塞后sem的值减一Q表明公p源经使用后减。函数sem_trywait ( sem_t *sem )是函数sem_waitQ)的非d版本Q它直接信号量sem的值减一?br>
函数sem_destroy(sem_t *sem)用来释放信号量sem?br>
下面我们来看一个用信号量的例子。在q个例子中,一共有4个线E,其中两个U程负责从文件读取数据到公共的缓冲区Q另两个U程从缓冲区d数据作不同的处理Q加和乘q算Q?br>
/* File sem.c */
#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#define MAXSTACK 100
int stack[MAXSTACK][2];
int size=0;
sem_t sem;
/* 从文?.datd数据Q每Mơ,信号量加一*/
void ReadData1(void){
FILE *fp=fopen("1.dat","r");
while(!feof(fp)){
fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);
sem_post(&sem);
++size;
}
fclose(fp);
}
/*从文?.datd数据*/
void ReadData2(void){
FILE *fp=fopen("2.dat","r");
while(!feof(fp)){
fscanf(fp,"%d %d",&stack[size][0],&stack[size][1]);
sem_post(&sem);
++size;
}
fclose(fp);
}
/*d{待~冲区有数据Q读取数据后Q释攄_l箋{待*/
void HandleData1(void){
while(1){
sem_wait(&sem);
printf("Plus:%d+%d=%dn",stack[size][0],stack[size][1],
stack[size][0]+stack[size][1]);
--size;
}
}
void HandleData2(void){
while(1){
sem_wait(&sem);
printf("Multiply:%d*%d=%dn",stack[size][0],stack[size][1],
stack[size][0]*stack[size][1]);
--size;
}
}
int main(void){
pthread_t t1,t2,t3,t4;
sem_init(&sem,0,0);
pthread_create(&t1,NULL,(void *)HandleData1,NULL);
pthread_create(&t2,NULL,(void *)HandleData2,NULL);
pthread_create(&t3,NULL,(void *)ReadData1,NULL);
pthread_create(&t4,NULL,(void *)ReadData2,NULL);
/* 防止E序q早退出,让它在此无限期等?/
pthread_join(t1,NULL);
}
在Linux下,我们用命令gcc -lpthread sem.c -o sem生成可执行文件sem?我们事先~辑好数据文?.dat?.datQ假讑֮们的内容分别? 2 3 4 5 6 7 8 9 10?-1 -2 -3 -4 -5 -6 -7 -8 -9 -10 Q我们运行semQ得到如下的l果Q?br>
Multiply:-1*-2=2
Plus:-1+-2=-3
Multiply:9*10=90
Plus:-9+-10=-19
Multiply:-7*-8=56
Plus:-5+-6=-11
Multiply:-3*-4=12
Plus:9+10=19
Plus:7+8=15
Plus:5+6=11
从中我们可以看出各个U程间的竞争关系。而数值ƈ未按我们原先的顺序显C出来这是由于sizeq个数D各个U程L修改的缘故。这也往往是多U程~程要注意的问题?br>
]]>
用语h亲缘关系q程间的通信
匿名一ơ性用的Q半双工。一个进E往输出端写道Q另一个进E从输入端读道?br> #include<unistd.h>
int pipe(int fd[2]);
fd[0]:表示ȝ
fd[1]:表示写端
2、有名管?named pipe)
允许无亲~关p进E间的通信
有名道Q作为特别文件存储于文gpȝ中。有名管道一旦徏立就存在于文件系l中Q除非显C的unlink
#include<sys/tpes.h>
#include<sys/stat.h>
int mknod(const char *path,mode_t mod,dev_t dev);
int mkfifo(const char *path,mode_t mode);
path:创徏有名道的全路径?br> mod:创徏有名道的模式,指存取权?br> dev:讑֤|该值取决于文g创徏的种c,它只在创备文件时才会用到
注意:有名道创徏后就可以使用了,有名道和管道的使用Ҏ基本是相同的。只是用有名管道的时候必d调用open()其打开
因ؓ有名道是一个存在于盘上的文gQ而管道是存在于内存中的特D文?/p>
下面的程序一个读道Q另一个写道Q这两个函数用的是非dd道
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"
main(int argc, char** argv)
{
char buf_r[100];
int fd;
int nread;
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
printf("cannot create fifoserver\n");
printf("Preparing for reading bytes...\n");
memset(buf_r,0,sizeof(buf_r));
fd=open(FIFO,O_RDONLY|O_NONBLOCK,0);
if(fd==-1)
{
perror("open");
exit(1);
}
while(1)
{
memset(buf_r,0,sizeof(buf_r));
if((nread=read(fd,buf_r,100))==-1){
if(errno==EAGAIN)
printf("no data yet\n");
}
printf("read %s from FIFO\n",buf_r);
sleep(1);
}
pause();
unlink(FIFO);
}
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FIFO "/tmp/myfifo"
main(int argc,char** argv)
{
int fd;
char w_buf[100];
int nwrite;
if(fd==-1)
if(errno==ENXIO)
printf("open error; no reading process\n");
fd=open(FIFO,O_WRONLY|O_NONBLOCK,0);
if(argc==1)
printf("Please send something\n");
strcpy(w_buf,argv[1]);
if((nwrite=write(fd,w_buf,100))==-1)
{
if(errno==EAGAIN)
printf("The FIFO has not been read yet.Please try later\n");
}
else
printf("write %s to the FIFO\n",w_buf);
}
3、信号量
主要用于q程间及同一q程不同U程之间的同步手D?/p>
4、消息队?/p>
克服信号量有限,可写可读
5、信PSignalQ?/p>
比较复杂Q用于通知接受q程有某事发?/p>
6、共享内?/p>
最有用的进E间通信方式Q得多个进E可讉K同以内存I间Q但需要依靠某U同步机?/p>
W一步:创徏׃n内存
W二步:映射׃n内存
7、套接字
不同机器之间通信