您的位置:首页 > 运维架构 > Linux

Linux系统编程的一些要点

2014-04-27 18:10 169 查看
Linux下的库有两种:静态库和共享库(动态库)。二者的不同点在于代码被载入的时刻不同。

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。
动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。

进程和程序的区别:

程序是静态的,它是一些保存在磁盘上的指令的有序集合,没有任何执行的概念。

- 包括指令、用户数据、

进程是一个动态的概念,它是程序执行的过程,包括创建、调度和消亡。
- 包括指令、用户数据、系统数据段

- 进程(线程)用结构体task_struct{}来表达。这个结构体通常被称为PCB(Process Control Block)

- 进程是资源管理的最小单位

- 线程是系统调度的最小单位

创建进程:pid_t fork()

使用以及注意事项参考:http://blog.csdn.net/jason314/article/details/5640969

回收进程:pid_t wait()

使用以及注意事项参考:http://www.cnblogs.com/linux-sir/archive/2012/01/27/2330014.html

exec函数族:

提供了一种在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段。在执行完之后,原调用进程的内容除了进程号外,其他全部都被替换了。

- 在使用exec函数族时,一定要加上错误判断语句

使用以及注意事项参考:http://www.farsight.com.cn/news/emb188.htm

exit() 和 _exit():

- exit(1)表示发生错误后退出程序, exit(0)表示正常退出

- exit() 会调用退出处理函数、请了I/O缓冲、调用exit系统调用

- _exit() 不会调用退出处理函数、请了I/O缓冲,只调用exit系统调用

----------------------------------------------------------------------

守护进程:

通常所说的Daemon进程,是Linux中的后台服务进程。它是一个生存期较长的进程,通常独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。

- 常常在系统引导装入时启动,在系统关闭时终止。

- 想让某个进程不因为用户或终端或其他的变化而受到影响,就必须把这个进程变成一个守护进程

Linux守护进程编写步骤:

1.  利用系统调用signal()忽略信号SIGHUP

2 . 利用系统调用fork()创建一个子进程p1

3.  在p1的基础上调用setsid(),创建一个新会话

4 . 利用系统调用fork()创建一个子进程p2

5 . 利用setpgrp()设置p2所在进程组

6 关闭所有文件描述符

7.  消除umask()的影响

8 . 修改守护进程的当前工作路径

9.  重定位标准输入输出和标准出错文件描述符

10.  打开系统日志文件

----------------------------------------------------------------------

Linux下进程间通信:

传统的进程间通信方式:

- 无名管道(pipe)

- 只能用于具有亲缘关系的进程之间的通信

- 半双工的通信模式,具有固定的读端和写端

- 管道可以看成是一种特殊的文件,对于它的读写可以使用文件IO如read、write函数

- 当管道中无数据时,读操作会阻塞

- 有名管道(fifo)

- 无名管道只能用于具有亲缘关系的进程之间,这就限制了无名管道的使用范围

- 有名管道可以使互不相关的两个进程互相通信。有名管道可以通过路径名来指出,并且在文件系统中可见

- 进程通过文件IO来操作有名管道

- 有名管道遵循先进先出规则

- 不支持如lseek() 操作

- 信号(signal)

使用以及注意事项参考:http://hutaow.com/blog/2013/10/19/linux-signal/

System V IPC对象

- 共享内存(share memory)

- 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝

- 为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间

- 进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高的效率。

- 由于多个进程共享一段内存,因此也需要依靠某种同步机制,如互斥锁和信号量等

- 消息队列(message queue)

- 消息队列由消息队列ID来唯一标识

- 消息队列就是一个消息的列表。用户可以在消息队列中添加消息、读取消息等。

- 创建或打开消息队列使用的函数是msgget,这里创建的消息队列的数量会受到系统消息队列数量的限制

- 添加消息使用的函数是msgsnd,按照类型把消息添加到已打开的消息队列末尾

- 读取消息使用的函数是msgrcv,可以按照类型把消息从消息队列中取走

- 控制消息队列使用的函数是msgctl,它可以完成多项功能。

- 信号量(semaphore)

使用以及注意事项参考:http://www.cnblogs.com/Anker/archive/2013/01/14/2859352.html

BSD

- 套接字(socket)

----------------------------------------------------------------------

LINUX线程:

线程:指的是共享相同地址空间的多个任务。

- 进程中的多个线程共享以下资源
- 可执行的指令 / 静态数据 / 进程中打开的文件描述符 / 信号处理函数 / 当前工作目录 / 用户ID / 用户组ID

- 每个线程私有的资源如下

- 线程ID (TID) / PC(程序计数器)和相关寄存器 / 堆栈 / 错误号 (errno) / 信号掩码和优先级 / 执行状态和属性

- 在Linux上线程函数位于libpthread共享库中,因此在编译时要加上-lpthread选项

创建线程:int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void * (* routine)(void *), void *arg)

结束线程:void pthread_exit(void *value_ptr)  //ptr用于存放线程结束的退出状态

如果需要只终止某个线程而不终止整个进程,可以有三种方法:

1、从线程函数return。这种方法对主线程不适用,从main函数return相当于调用exit,而如果任意一个线程调用了exit或_exit,则整个进程的所有线程都终止

2、一个线程可以调用pthread_cancel 终止同一进程中的另一个线程。

3、线程可以调用pthread_exit终止自己。

线程分离:int pthread_detach(pthread_t thread);

- 不能对一个已经处于detach状态的线程调用pthread_join,这样的调用将返回EINVAL

- 对一个尚未detach的线程调用pthread_join或pthread_detach都可以把该线程置为detach状态

使用及注意参考:http://blog.csdn.net/trinea/article/details/5191165

取消线程:int pthread_cancel(pthread_t thread);

使用及注意参考:http://my.oschina.net/u/178323/blog/32535

线程等待:int pthread_join(pthread_t thread, void **value_ptr)

调用该函数的线程将挂起等待,直到id为thread的线程终止。thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的,总结如下:

1、如果thread线程通过return返回,value_ptr所指向的单元里存放的是thread线程函数的返回值。
2、如果thread线程被别的线程调用pthread_cancel异常终止掉,value_ptr所指向的单元里存放的是常数PTHREAD_CANCELED。

3、如果thread线程是自己调用pthread_exit终止的,value_ptr所指向的单元存放的是传给pthread_exit的参数。

更详细见:http://blog.csdn.net/chenkjiang/article/details/12112895

----------------------------------------------------------------

线程间机制

- 多线程共享同一个进程的地址空间

多线程同步互斥机制:

- 信号量 

P操作:申请资源  int sem_wait(sem_t *sem);

当信号量的值等于0时,该操作将可能引起线程睡眠

当信号量的值大于0时,该操作将会使得其值减1

V操作:释放资源  int sem_post(sem_t *sem);

当当前没有线程正在等待该信号量时,该操作将使得其值加1

当当前有线程正在等待该信号量时,该操作将唤醒该线程

- 互斥锁 

- 主要用来保护临界资源, 任何时刻最多只能有一个线程能访问该资源

- 在主线程中初始化锁为解锁状态

pthread_mutex_t mutex;

pthread_mutex_init(&mutex, NULL);

- 在编译时初始化锁为解锁状态

- 锁初始化 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

- 访问对象时的加锁操作与解锁操作

加锁 pthread_mutex_lock(&mutex)

释放锁 pthread_mutex_unlock(&mutex)

/ 读写锁 / 记录锁 / 条件变量

使用以及注意事项参考:http://www.cnblogs.com/fuyunbiyi/p/3475602.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: