自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

luciusvorenus

转行之路长漫漫

  • 博客(121)
  • 收藏
  • 关注

原创 哲学家用餐模型

分析:为了避免死锁,做了如下规定:每个哲学家先拿自己左手边的筷子,然后再去拿右手边的筷子,如果不能同时得到两支筷子,则该哲学家放下手中已有的筷子。这种规定依然会因为振荡而产生死锁,例如:每个哲学家都同时拿上了左手边的筷子,然后都阻塞,都释放左手筷子;然后又同时去拿左手边的筷子,这样周而复始,一直进行下去,就是因为振荡而产生的死锁。解决方法:规定其中一位哲学家先拿右手边的筷子,再拿左手边的筷子即...

2019-04-23 21:48:33 717

原创 文件锁

借助 fcntl函数来实现文件锁机制。操作文件的进程没有获得文件锁时,可以打开文件,但无法执行read、write操作。 注意,文件锁只能用于进程间同步!fcntl函数:int fcntl(int fd, int cmd);int fcntl(int fd, int cmd, long arg);//long 长整型int fcntl(int fd, int cmd, struct...

2019-04-23 21:46:58 537

原创 进程间同步(互斥量、信号量)

进程间同步可以使用互斥量mutex(互斥锁)、信号量和文件锁。进程间同步使用信号量:int sem_init(sem_t *sem, int pshared, unsigned int value);用于进程间同步此时第二个参数不能取0了,取非0值用于进程间同步,一般取1,也可按照下述方法取值,即:PTHREAD_PROCESS_SHARED。(1)进程间使用互斥量进行同步在p...

2019-04-23 21:45:41 2848

原创 信号量

信号量称为进化版的互斥锁。由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁是没有办法实现的,只能将整个数据对象锁住。这样虽然达到了多线程操作共享数据时保证数据正确性的目的,却无形中导致线程的并发性下降。线程从并行执行,变成了串行执行。与直接使用单进程无异。信号量,是相对折中的一种处理方式,既能保证同步,数据不混乱,又能提高线程并发。例如,有5台打印机被多个线...

2019-04-23 21:43:44 4302

原创 条件变量

条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所(共享的数据)。主要应用函数:pthread_cond_init函数 pthread_cond_destroy函数pthread_cond_wait函数 pthread_cond_timedwait函数pthread_cond_signal函数 pthread...

2019-04-23 21:42:02 4134

原创 读写锁

与互斥量类似,但读写锁允许更高的并行性。其特性为:写独占,读共享。一把读写锁具备三种状态:读模式下加锁状态 (读锁);写模式下加锁状态 (写锁);不加锁状态。引入读写锁的目的:在对共享资源既进行读取,又进行写操作(修改)的情况下,使用读写锁比使用互斥锁(mutex)的效率更高,因为使用读写锁时,允许多个读线程同时读取。特别是当读操作的线程远大于写操作的线程时,这种效果更加明显。(1)读写锁...

2019-04-23 21:41:03 434

原创 死锁

死锁的现象:1. 线程试图对同一个互斥量A加锁两次。这种情况主要是在编程时不经意之间发生的。当对互斥量加锁后,如果再次加锁导致该线程阻塞等待锁被释放,但是该锁其实就被线程自己占有了,因此造成了自己把自己死锁住了。解决方法:在加锁之前应该检查之前是否加过锁还未解锁;2. 当线程要同时获得多个共享资源才能完成工作时,如线程1拥有A锁,请求获得B锁;线程2拥有B锁,请求获得A锁。解决方法:当线程...

2019-04-23 21:39:52 139

原创 互斥量(mutex)

Linux中提供一把互斥锁mutex(也称之为互斥量)。每个线程在对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁。资源还是共享的,线程间也还是竞争的,但通过“锁”就将资源的访问变成互斥操作,而后与时间有关的错误也不会再产生了。但,应注意:同一时刻,只能有一个线程持有该锁。当A线程对某个全局变量加锁访问,B在访问前尝试加锁,拿不到锁,B阻塞。C线程不去加锁,而直接访问该全局变量,依然能...

2019-04-23 21:39:25 1898

原创 线程同步的概念

所谓同步,即同时起步,协调一致。不同的对象,对“同步”的理解方式略有不同。如,设备同步,是指在两个设备之间规定一个共同的时间参考;数据库同步,是指让两个或多个数据库内容保持一致,或者按需要部分保持一致;文件同步,是指让两个或多个文件夹里的文件保持一致。而编程中、通信中所说的同步主旨在协同步调,按预定的先后次序运行。线程同步,指一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其...

2019-04-23 21:38:13 995

原创 线程使用注意事项

1.主线程退出其他线程不退出,主线程应调用pthread_exit;2.避免僵尸线程:pthread_join、pthread_detach、pthread_create指定分离属性。被join线程可能在join函数返回前就释放完自己的所有内存资源,所以不应当返回被回收线程栈中的值;(因为此时释放的栈空间又可能被重新分配出去,此时得到的返回值没有意义)3.malloc和mmap申请的内存可...

2019-04-20 23:58:03 695

原创 NPTL(Native POSIX Thread Library)

1.NPTL(Native POSIX Thread Library)为POSIX标准线程库,查看当前Linux系统的pthread库(线程库)版本的命令为:getconf GNU_LIBPTHREAD_VERSION。[root@localhost 01_pthread_test]# getconf GNU_LIBPTHREAD_VERSIONNPTL 2.17注意:同样的程序,如果...

2019-04-20 23:57:36 494

原创 线程属性的修改

(1)线程属性Linux下线程的属性是可以根据实际项目需要,进行设置,之前我们讨论的线程都是采用线程的默认属性,默认属性已经可以解决绝大多数开发时遇到的问题。如我们对程序的性能提出更高的要求那么需要设置线程属性,比如可以通过设置线程栈的大小来降低内存的使用,增加最大线程个数。typedef struct{int detach...

2019-04-20 23:56:58 1145

原创 线程与进程的控制原语对比

线程与进程的控制原语对比 fork pthead_create exit( int ) pthead_exit(void *); wait(int *) pthread_join( ,void **) 阻塞 ;分离 22 ;cancel -1 kill() ...

2019-04-20 23:55:12 363

原创 pthread_cancel、pthread_equal函数

(1)pthread_cancel函数int pthread_cancel(pthread_t thread); 成功:0;失败:错误号作用:杀死(取消)线程,其作用对应进程中 kill() 函数。注意:线程的取消并不是实时的,而有一定的延时。需要等待线程到达某个取消点(检查点)。杀死线程不是立刻就能完成,必须要到达取消点。取消点:是线程检查是否被取消,并按请求进行动作的一个位置...

2019-04-20 23:54:41 1837

原创 pthread_detach函数

int pthread_detach(pthread_t thread); 成功:0;失败:错误号作用:从状态上实现线程分离,注意不是指该线程独自占用地址空间。线程分离状态:指定该状态,线程主动与主控线程断开关系。线程结束后(不会产生僵尸线程),其退出状态不由其他线程获取,而直接自己自动释放(自己清理掉PCB的残留资源)。网络、多线程服务器常用。进程若有该机制,将不会产生僵尸进程...

2019-04-20 23:52:21 33877

原创 pthread_join函数

int pthread_join(pthread_t thread, void **retval);作用:阻塞等待线程退出,获取线程退出状态。其作用对应进程中 waitpid() 函数。成功:0;失败:错误号 strerror函数参数:thread:线程ID (注意:不是指针);retval:存储线程结束状态。对比记忆:在wait回收子进程时,子进程exit或return返回的...

2019-04-20 23:51:23 6112 1

原创 pthread_exit函数

void pthread_exit(void *retval); 参数:retval表示线程退出状态,通常传NULL。作用:将单个线程退出。注意几点:return的作用是返回到函数的调用点,如果是main函数中的return,则代表该进程结束,并释放进程地址空间,所有线程都终止。对于其它函数的return,则直接返回到函数的调用点。exit和_exit函数会直接终止整个进程,导致所有线...

2019-04-20 23:50:17 4722

原创 线程共享全局变量(.data和.bbs)

线程默认共享数据段、代码段等地址空间,常用的是全局变量。而进程不共享全局变量,只能借助mmap。//代码示例#include <string.h>#include <stdio.h>#include <pthread.h>#include <stdlib.h>#include <string.h>#include &l...

2019-04-20 23:48:34 663

原创 C指针深度解析

(1)指针的概念指针是一种数据类型,而内存地址是这种数据类型具体的值(注意区分两者的概念)。先说一下什么是内存地址:假设CPU的寻址方式是以字节寻址的,即每一个字节对应一个地址编号(则机器字长、存储字长和数据字长都是字节的整数倍,所有的数据类型占据的空间大小都是字节的整数倍)。对于32位操作系统,地址码最长可达32位,则可以寻址的最大数目为:=4G,由于最小单位是字节,因此可寻址的最大内存为4...

2019-04-19 18:41:21 214

原创 线程控制原语之pthread_self和pthread_create函数

注意:使用线程库函数用gcc编译时,要加参数:-lpthread(libpthread.so),因为线程库函数属于第三方c库函数,不是标准库函数(/lib、/usr/lib或者/usr/local/lib)。(1)pthread_self函数获取线程ID。其作用对应进程中 getpid() 函数。pthread_t pthread_self(void); 返回值:成功:调用该函数的...

2019-04-17 12:06:21 3509

原创 线程的概念

线程(LWP,light weight process)是轻量级的进程,本质仍是进程(在类unix环境下)。进程有独立地址空间,拥有PCB;线程也有PCB,但没有独立的地址空间(共享)。在Linux下,线程是最小的执行单位;进程是最小分配资源单位,可看成是只有一个线程的进程。(1)Linux内核线程实现原理类Unix系统中,早期是没有“线程”概念的,80年代才引入,借助进程机制实现出了线程...

2019-04-17 00:43:10 240 1

原创 网络终端

虚拟终端或串口终端的数目是有限的,虚拟终端(字符控制终端)一般就是/dev/tty1∼/dev/tty6六个,串口终端的数目也不超过串口的数目。然而网络终端或图形终端窗口的数目却是不受限制的,这是通过伪终端(Pseudo TTY)实现的。一套伪终端由一个主设备(PTY Master)和一个从设备(PTY Slave)组成。主设备在概念上相当于键盘和显示器,只不过它不是真正的硬件而是...

2019-04-17 00:32:35 881

原创 守护进程

Daemon(精灵)进程,是Linux中的后台服务进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。一般采用以d结尾的名字。如vsftpd 、httpd、 sshd、xinetd、mysql服务器,守护进程本质上是一个后台系统服务器(一直在后台运行)。Linux后台的一些系统服务进程,没有控制终端,不能直接和用户交互。不受用户登录、注销的影响,一直在运行着,他们都是守...

2019-04-17 00:32:14 214

原创 会话(session)

一组进程形成一个进程组,一组进程组形成一个会话,即一个会话中可以包括多个进程组。(1)创建会话创建一个会话需要注意以下6点注意事项:1.调用进程不能是进程组组长(不能是父进程),该进程变成新会话首进程(session header) ,若调用进程是组长进程,则出错返回;2.该进程成为一个新进程组的组长进程;3.需有root权限(ubuntu不需要);4.新会话丢弃原有的控制终端,该会话没有...

2019-04-17 00:31:51 428

原创 进程组(作业)

(1)概念和特性进程组,也称之为作业。BSD于1980年前后向Unix中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在waitpid函数和kill函数的参数中都曾使用到。操作系统设计的进程组的概念,是为了简化对多个进程的管理。当父进程,创建子进程的时候,默认子进程与父进程属于同一进程组。进程组的ID就是该进程组组长的ID,也就是父进程的ID。一个进程只有一个进程组...

2019-04-17 00:31:30 213

原创 终端的启动流程

在Linux操作系统启动时,首先加载的进程就是init进程(ID为1),其余进程都是init进程产生的(fork,然后exec金蝉脱壳),因此系统中所有进程都可以看成是init进程的子孙进程。可以通过ps ajx命令查看任意进程的父进程,进行追溯可以发现,任意进程的开头都是init进程,init进程起源于0号进程,0号进程实际不存在。文件与I/O中讲过,每个进程都可以通过一个特殊的设备文件/d...

2019-04-16 06:05:43 614

原创 终端的概念

操作系统接口:用户接口和程序接口。用户接口分为联机用户接口和脱机用户接口。脱机用户接口出现在早期的批处理系统中(将作业提前交给操作系统,作业完成的过程中用户无法交互);联机用户接口即为终端(所有输入输出设备),包括设备终端(伪终端,pseudo terminal slave)、文字终端(字符终端)和桌面终端(图形界面终端),联机用户接口可以使用户与操作系统实时交互。而程序接口就是指操作系统提供的各...

2019-04-16 06:03:56 1933

原创 中断系统调用

系统调用可分为两类:慢速系统调用和其它系统调用。慢速系统调用:可能会使进程永远阻塞的一类的系统调用。如果在阻塞期间收到一个信号,该系统调用就被中断,不再继续执行(早期);也可以设定系统调用是否重启。如,read、write、pause、wait、waitpid等。read在读管道、读网络和读设备(如从键盘上读,标准输入设备)都可能会永久阻塞(只要数据不到达,read就会阻塞读),但是read读...

2019-04-16 06:03:26 676

原创 信号传参

(1)发送信号传参前面已经知道从一个进程向另一个进程发送信号可以使用kill函数,但是kill函数在向进程发送信号的时候不能携带除了信号以外的其他信息,这时可以使用与kill相对应的sigqueue函数,该函数也是向一个进程发送信号,但是可以携带其它参数信息:int sigqueue(pid_t pid, int sig, const union sigval value); 成功:0;失...

2019-04-16 06:02:43 566

原创 SIGCHLD信号

(1)SIGCHLD信号产生的条件1.子进程终止时会向父进程发送SIGCHLD信号,告知父进程回收自己,但该信号的默认处理动作为忽略,因此父进程仍然不会去回收子进程,需要捕捉处理实现子进程的回收;2.子进程接收到SIGSTOP(19)信号停止时;3.子进程处在停止态,接受到SIGCONT后唤醒时。综上:子进程结束、接收到SIGSTOP停止(挂起)和接收到SIGCONT唤醒时都会向父...

2019-04-16 06:02:07 18187 2

原创 可/不可重入函数

一个函数在被调用执行期间(尚未调用结束),由于某种时序(递归或者处理信号捕捉时等情况)又被重复调用,称之为“重入”。根据函数实现的方法可分为“可重入函数”和“不可重入函数”两种。看如下程序。可以看出在进程主控程序的insert函数未执行完时(在执行完p->next=head时,收到一个信号,需要立即去处理信号),马上内核接着调用了insert函数来将node2节点插入链表。预期结果应...

2019-04-16 06:00:43 1335

原创 全局变量的异步I/O问题

全局变量的异步I/O问题同样属于时序竞态问题,其本质就是多个进程或者同一个进程中的多个时序(如主控程序和信号捕捉时的用户处理函数)对同一个变量进行修改时,它们的执行顺序不一样就会导致该变量最终的值不一样,从而产生不一样的结果。多个进程或者同一个进程中的多个时序对同一个变量进行操作时,应该尽量避免使用这种变量。在编程时也应当尽量避免使用全局变量。如果非用不可,则必须考虑该全局变量的使用顺序问题,...

2019-04-16 05:56:18 835

原创 sigsuspend函数(mysleep函数的改进)

可以通过设置屏蔽SIGALRM的方法来控制程序执行逻辑,但无论如何设置,程序都有可能在“解除信号屏蔽”与“挂起等待信号”这个两个操作间隙失去cpu资源。除非将这两步骤合并成一个“原子操作”。sigsuspend函数具备这个功能。在对时序要求严格的场合下都应该使用sigsuspend替换pause。信号被解除屏蔽和进程挂起等待(sigsuspend函数执行)是同时进行的,为原子操作,不可分割。i...

2019-04-16 05:54:28 316

原创 时序竞态(竞态条件)

产生原因:仍然以前文实现的sleep函数为例,如果进程在执行完alarm函数后,突然失去CPU,被阻塞等待(这是有可能的,进程在执行过程中,若非原子操作,都有可能随时失去CPU),如果失去CPU的时间大于了sleep函数需要睡眠的时间,则此时在执行pause函数前,信号已经到了,因此会先处理信号(软中断,而不是先执行pause函数),在信号处理完后,再去执行pause函数,此时进程会被永远挂起,不...

2019-04-16 05:53:16 996

原创 pause函数

调用该函数(系统调用)的进程将处于阻塞状态(主动放弃cpu),直到有信号递达将其唤醒。int pause(void); 返回值:-1 并设置errno为EINTR 该函数只有一个返回值,可以理解为只有成功返回值,且为-1,同时errno的值置为EINTR。注意,只有当一个信号递达且处理方式被捕捉时,pause函数引起挂起操作的进程才会被唤醒,而且只有当信号处理完后(调用完用户处理函数)...

2019-04-16 05:52:25 11763

原创 信号捕捉(signal、sigaction)

信号的基本属性:软中断,由内核发送,内核处理。某个进程通过内核向另一个进程发送信号时(引起信号产生的五个因素),另一个进程将会陷入内核进行中断处理,未决信号集中相应信号置1,当递达后,置0。如果阻塞信号集相应信号为1,则该信号处于未决状态。处于未决状态中的信号,多次发送时,只是执行一次,因为在未决信号集中只是记录了该信号的状态,没有记录发送的次数。信号抵达后,内核进行处理。处理方式有三:默认处理方...

2019-04-01 23:43:54 1953

原创 信号集操作函数

内核通过读取未决信号集来判断信号是否应被处理。信号屏蔽字mask可以影响未决信号集。而我们可以在应用程序中自定义set来改变mask。已达到屏蔽指定信号的目的。综上:自定义信号集set(也为一个字,64位)通过信号集操作函数来改变信号屏蔽字mask,然后mask进一步来影响未决信号集,从而控制信号是否应该被屏蔽。后面我们只是研究常规信号,即1~31号!(1)信号集的设置sigset_t ...

2019-04-01 23:40:55 361

原创 信号的产生

(1)终端按键产生信号(与终端交互的进程)Ctrl + c → 2) SIGINT(终止/中断) "INT" ----InterruptCtrl + z → 20) SIGTSTP(暂停/停止) "T" ----Terminal 终端 此时进程处于后台运行Ctrl + \ → 3) SIGQUIT(退出)(2)硬件异常产生信号除0操作 → 8) ...

2019-04-01 23:39:35 165

原创 信号四要素

与变量三要素(类型、名字、值)类似的,每个信号也有其必备4要素,分别是:1.编号;2.名称(即编号的宏定义) ;3.事件(引起信号产生的事件,如段错误);4.默认处理动作可以通过man 7 signal 命令查看:Signal Value Action Comment──────────────────────────────────SIGALRM ...

2019-03-31 23:41:44 728

原创 信号的产生和状态

信号的产生:1.按键产生,如:Ctrl+c(内核向进程发送信号,杀死该进程)、Ctrl+z、Ctrl+\;2.系统调用产生,如:kill、raise、abort;3.软件条件产生,如:定时器alarm;4.硬件异常产生,如:非法访问内存(段错误)、除0(浮点数例外)、内存对齐出错(总线错误);5.命令产生,如:kill命令。递达:递送并且到达进程。未决:产生和递达之间的状态。主要由于阻塞(...

2019-03-31 23:40:46 560

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除