Category Archives: Linux

UNIX进程控制

1. 交换进程与init进程
进程ID0是调度进程,常常被称为交换进程(swapper)。该进程并不执行任何磁盘上的程序。它是内核的一部分,因此也被称为系统进程。
进程ID1通常是init进程,在自举过程结束时由内核调用(swapper进程创建一个内核线程,然后exec来执行init)。该进程的程序文件/sbin/init。此进程负责在内核自举后启动一个UNIX系统。init通常读与系统有关的初始化文件(/etc/rc*),并将系统引导到一个状态(例如多用户)。虽然init是一个普通的用户进程(swapper进程是内核的系统进程而非用户进程),但init进程决不会终止。但是它以超级用户特权运行。
在某些UNIX的虚存实现中,进程PID=2是页精灵进程(page daemon)。此进程负责支持虚存系统的请页操作。与交换进程一样,页精灵进程也是内核进程。
Continue reading

Posted in C|C++, Linux.

几个字符串问题的awk解法

1.输入:一个文本文件,第一行是一个数字n,其他每行分别是一个单词以及它出现的百分比。
输出:输出n个单词,每个单词出现的几率符合它的百分比。

awk ‘BEGIN{sum=0;}1{n=$0}2,${up=sum+$1;while(sum< $1){arr[sum]+=$2;sum++;}if(i>100){exit 1;}}END{while(–n>0){print arr[rand()%100];}’
Continue reading

Posted in Linux.

UNIX进程组,会话和作业控制

1. 进程组、会话与终端

(1).每个进程都属于一个进程组。进程组是一个或多个进程的集合,通常它们与一组作业相关联,可以接受来自同一终端的各种信号。每个进程组都有唯一的进程组ID(整数,也可以存放在pid_t类型中)。返回值是调用进程的进程组ID

每个进程组都有一个组长进程,组长进程的标识是进程组ID等于其进程ID。组长进程可以创建一个进程组、创建该组中的进程。只有某个进程中有一个进程存在,则该进程就存在,与组长进程是否终止无关。从进程组创建开始到其中最后一个进程离开为止的时间区间成为进程组的生存期。进程组中最后一个进程可以终止或者转移到另一个进程组中。
Continue reading

Posted in C|C++, Linux.

用perl和bash批量修改文件名

需求:某个目录下有若干日志文件,文件名是log.2011mmddhhmmss(mmddhhmmss为任意的时间戳),更改成log.2012mmddhhmmss。
这里必然用到正则表达式,首先想到一个Perl的实现

用bash实现关键用for i in ls来获得各个文件名,然后用管道和sed。

Posted in Linux.

【APUE】I/O复用

1. 概念

当从一个fd读,写到另一个fd时,可以在下列形式的循环中使用阻塞I/0。

但是如果必须从两个fd中读,如果仍然使用阻塞式I/O,那么程序就会长时间阻塞在一个描述符上。这在网络编程中需要多个socket中获取数据的情况尤为常见。
解决方法一般有如下几种:
a).使用多进程/线程模型,每个进程/线程阻塞式等待一个fd。但是需要之间的多个信号通信机制,增加了程序的复杂性。
b).使用非阻塞式I/O(open with O_NOBLOCK),不断轮询(polling)多个描述符。但浪费CPU时间,并且多次执行read的系统调用。每次polling一遍后应该sleep若干时间,但这个时间很难确定。
c).使用信号驱动I/O模型。首先用sigaction设置SIGIO的信号处理程序,这样内核在数据ready的时候就发送一个SIGIO给进程,进程用信号处理程序接收并处理,完成时成功返回。
d).使用异步I/O(asynchronous I/O)。基本思想是进程告诉内核,当一个fd已经ready的时候,用一个signal通知它。需要注意的是,并非所有的UNIX系统都支持。(System V为这种机制提供了SIGPOLL信号,但是仅当fd是STEAMS设备的时才可用。另外这个信号对每个进程而言只有一个,如果该信号对两个fd都起作用则无法判断哪一个已经ready。为了确定,则将多个fd都设为非阻塞的,以此read来判断)。Linux支持异步I/O但是不默认支持STREAMS机制。与信号驱动I/O相比,信号驱动是通知发起时通知进程,然后将数据从内核读到进程空间。而异步I/O是完成全部过程才通知进程。
e).使用I/O复用(I/O multiplexing)。先构造一张有关fd的列表,然后调用一个函数。直到fd中一个已经准备进行I/O时,这个函数才返回。多路转接是这种问题实现的最好方式。具体函数介绍如下。

2.select和pselect函数

select函数使我们可以执行I/0多路转接,传向select的参数告诉内核:
(1).关心的fd
(2).对于每个fd关心的状态。(读,写或者异常)
从select返回,内核告诉我们:
(1).已经准备号的fd数量。
(2).对于读,写或者异常这三个状态中的每一个,哪些描述符已经准备好。

该函数提供了一种在单个进程中监视多个文件描述符的方法。可以对三种类型的描述符集进行监视:可读(第2个参数:readfds)、可写(第3个参 数:writefds)、处于异常状态(第4个参数:exceptfds)的描述符。从第2个参数起,参数都可以为空(NULL),当文件描述符集为空时,表示不监视其描述符的状态;nfds 是三个文件描述符号中最大的描述符+1。这样就会在一定的范围内搜索需要检测的描述符,否则,将会在所有可选的fd_set中搜索。
最后一个描述符为愿意等待的时间,

timeval *timeout有三种情况
a). timeout == NULL 表示永远阻塞,直到fd准备好。
b). timeout->tv_sec == 0 && timeout->tv_usec == 0 表示完全不等待,测试所有的fd并立即返回。这样得到多个fd的状态而不阻塞select函数的polling方法。
c). timeout->tv_sec != 0 && timeout->tv_usec != 0 等待指定的秒数和毫秒数。当指定的fd之一已经ready时,或者指定时间到达时立即返回。如果是超时时返回则返回0。

Reference:
APUE Chapter 14
UNP Chapter 6

Posted in C|C++, Linux.

GDB & core dump

一、core dump

1.何谓 core dump?

我们在开发(或使用)一个程序时,最怕的就是程序莫明其妙地当掉。虽然系统没事,但我们下次仍可能遇到相同的问题。于是这时操作系统就会把程序当掉 时的内存内容 dump 出来(现在通常是写在一个叫 core的file里面),让 我们或是debugger 做为参考。这个动作就叫作 core dump。
在 C/C++语言中,最常发生错误的地方就是指 针有问题。您可以利用 core 文件和debugger工具(gdb)把错误找出来。除了SIGSEGV(无效内存访问)信号以外,SIGABRT(异常终止), SIGBUS(硬件故障),SIGEMT(硬件故障),SIGFPE(算术异常),SIGILL(非法硬件指令),SIGIOT(硬件故障),SIGQUIT,SIGSYS(无效系统调用),SIGTRAP(硬件故障)等。
Continue reading

Posted in C|C++, Linux.

【APUE】守护进程

概念

守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程常常在系统引导装入时启动,在系统关闭时终止。Linux系统中大多数服务和系统任务都是通过守护进程实现的。例如,作业规划进程crond、打印进程lqd、nfsd、lockd、rpciod(这三个是NFS的守护进程)、portmap(端口映射守护进程提供将RPC程序号映射为port好的服务)、bdflush(当内存达到下限时,将buffer cache flush到磁盘上)、kupdated(每隔一段时间,kupdated将dirty page flush到磁盘上以免数据丢失)、syslogd(由帮助操作人员把系统消息记入日志的任何程序使用)、crond(指定的日期和时间执行命令)。

创建守护进程

(1).创建子进程,父进程退出,这样让init收养子进程。
(2).调用setsid子进程中创建新会话
会话周期:会话期是一个或多个进程组的集合。通常,一个会话开始与用户登录,终止于用户退出,在此期间该用户运行的所有进程都属于这个会话期。
Continue reading

Posted in C|C++, Linux.

pthread线程和信号

pthread线程和信号
所有的异步信号发到整个进程的所有线程(异步信号如kill, lwp_kill, sigsend, kill等调用产生的都是,异步信号也称为中断),而且所有线程共享信号的处理行为(即sigaction的设置,对于同一信号的设置,某一线程的更改会影响到所有线程)。但每个线程可以有自己的mask来阻止信号的发送,所以可以通过线程对mask的设置来决定信号发送到哪个线程。
Continue reading

Posted in C|C++, Linux.

pthread线程私有数据

线程私有数据是存储和查询与某个线程相关的数据的一种机制。把这种数据称为线程私有/特定数据的原因是希望每个线程可以独立地访问数据副本而无需担心数据同步问题。
设计线程私有数据接口的原因是:(1).线程ID不能保证是小而连续的整数。例如上一章的程序threadid得到的结果:
main thread: pid 9508 tid 1611388704 (0x600bd720)
new thread: pid 9508 tid 1603331840 (0x5f90e700)
Continue reading

Posted in C|C++, Linux.

pthread线程同步机制

1.互斥量
当多个控制线程共享相同的内存时,需要确保每一个线程看到一致数据视图。如果不存在读取数据或者所有数据只读时不会存在一致性问题。如果某个线程正在修改变量而其他线程也可以读取或者修改这个变量的时候就需要对这些线程进行同步。在变量修改多于一个存储器访问周期时可能出现不一致的错误。(例如需要写的十一个长类型,需要多次写入内存。而写之间如果有其他线程读取就会出现同时读取一些修改过和没修改过的数据)。
通过使用pthread的互斥接口保护数据,确保同一时间只有一个线程访问数据。互斥量mutex本质上是一把锁,在访问共享资源前对互斥量加锁,然后其他任何试图访问互斥量加锁的线程将会被阻塞。访问完成后释放互斥量上的锁,被阻塞的线程将会变成可运行状态。同理,第一个变为可运行状态的进程将会锁住信号量,这样后面要访问该互斥量线程会被继续阻塞,直到回去再次等待它重新变为可用。
互斥量用pthread_mutex_t数据类型表示,在使用互斥量以前,必须首先对它进行初始化,可以把它置为常量PTHREAD_MUTEX_INITIALIZER(只对静态分配的互斥量)或者使用pthread_mutex_init函数进行初始化。如果动态分配(malloc)那么释放内存前需要调用(pthread_mutex_destroy)

Continue reading

Posted in C|C++, Linux.