[关闭]
@rfish 2015-08-25T08:33:08.000000Z 字数 10736 阅读 2437

系统

培训


一. 名词解释


二. 进程

2.1 进程状态

主要状态:

其他状态:

关于sleep( ):

2.2 进程的调用

  1. +---------+ +---------+
  2. | Stack | | Stack |
  3. +---------+ +---------+
  4. | Heep | fork() | Heep |
  5. +---------+ +--------> +---------+
  6. | DATA | | DATA |
  7. +---------+ +---------+
  8. | Code | | Code |
  9. +---------+ +---------+
  1. pid_t fork();
  2. //返回生成的子进程的pid(数据类型为pid_t,也是int)

说明:
在父进程中fork()返回的是子进程ID号,在fork出来的子进程中返回的是0。

返回值:
- <0:创建失败
- >0:当前运行在父进程
- =0:当前运行在子进程

  1. +---------+
  2. | Stack |
  3. +---------+
  4. | deep |
  5. +---------+
  6. | DATA |
  7. +---------+ exec函数族
  8. | | -----------+
  9. | | |
  10. | Code | |根据exec函数族的程序路径参数,将代码覆盖掉。
  11. | | |
  12. | | <----------+
  13. +---------+
  14. 会将原先进程的代码全部覆盖

2.3 进程的退出

  1. #include<sys/types.h>
  2. #include<sys/wait.h>
  3. int status;//用以保存子进程的状态
  4. pid_t pid=wait(&status);
  5. //wait可以接收子进程的exit的状态,也可以回收子进程的资源
  6. WEXITSTATUS(stata);
  7. //解析子进程退出返回的状态。

2.4 进程间通信

2.4.1 方式

方式 函数 说明
文件 对同一文件读写
mmap mmap() 父子间通信,MAP_SHARED
有名管道 mkfifo(); 同一系统任意进程间通信,有实际的管道文件
无名管道 pipe(); 只适用于父子间通信,没有实际的管道文件
信号 kill()alarm()raise() signal()拦截信号
IPC 消息队列 ftok()msggetmsgsndmsgrcvmsgctl
IPC 共享内存 ftok()shmgetshmatshmdtmsgctl
IPC 信号量 semgetsemctlsemop semget 返回semid

当子进程退出的时候会发送SIGCHLD信号给父进程,父进程可接收该信号,调用wait回收子进程

发送信号函数特性:

  • kill
    • 可以发给任何进程
  • alarm
    • 只能发给自己只能是SIGALRM信号
    • 可以设置发送定时
    • 一次调用只能发送一次
  • raise
    • 只能发给本进程
    • 可以定制发送的信号
    • 立即发送

pause();函数会暂停程序,当接收到SIGCONT信号才会继续运行。

2.4.2 有名管道

适用:同一系统的任意进程

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. int mkfifo(const char *pathname, mode_t mode);
  4. //pathname:要创建的管道文件路径
  5. //mode:文件权限

mode specifies the FIFO's permissions. It is modified by the process's umask in the usual way:the permissions of the created file are (mode & ~umask).

2.4.3 消息队列

  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. key_t ftok(const char *pathname, int proj_id);//proj_id只有低八位有效0-255
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. int msgget(key_t key, int msgflg);//返回队列描述符
参数 说明
int msgflg IPC_CREAT 创建队列
IPC_EXCL 如果队列存在就会出错---errno 是否等于EEXIST
与权限相或例如: IPC_CREAT|0777
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. struct msgbuf {
  5. long mtype; /* message type, must be > 0 */
  6. char mtext[1]; /* message data */
  7. char m[1000];
  8. };
  9. int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
函数 参数 说明
msgsnd() 返回值 -1失败,0表示成功
int msgid 消息队列描述符
const void *msgp 发送消息结构地址
size_t msgsz 消息正文长度
int msgflg 0(发送完才返回) IPC_NOWAIT
  1. ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,
  2. int msgflg);
函数 参数 说明
msgrcv() 返回值 -1失败, 接收字节数(成功)
void *msgp 接收消息结构地址
size_t msgsz 接收消息正文长度
long msgtyp 接收消息类型(编号),msgtyp相同才接收
int msgflg 0(接收如果没有数据就会阻塞) IPC_NOWAIT
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/msg.h>
  4. int msgctl(int msqid, int cmd, struct msqid_ds *buf);
函数 参数 说明
msgctl() int cmd IPC_STAT获取状态放在struct msqid_ds *buf
IPC_SET把struct msqid_ds *buf设置到消息队列
IPC_RMID删除消息队列 struct msqid_ds *buf填NULL

2.4.4 共享内存

  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. key_t ftok(const char *pathname, int proj_id);//proj_id只有低八位有效0-255
  1. #include <sys/ipc.h>
  2. #include <sys/shm.h>
  3. int shmget(key_t key, size_t size, int shmflg);
  4. 返回值:int ---获取到的共享内存id(描述符)
  5. 参数:
  6. key_t key -- ipc键值
  7. size_t size---共享内存空间大小(一般一页整数倍)getpagesize
  8. int shmflg----IPC_CREAT创建---权限
  1. #include <sys/types.h>
  2. #include <sys/shm.h>
  3. void *shmat(int shmid, const void *shmaddr, int shmflg);
  4. 返回值:成功(映射到用户空间的首地址) 失败((void*)-1
  5. 参数:
  6. int shmid----共享内存id
  7. const void *shmaddr---用户空间地址与内存空间映射用(一般NULL系统自动分配)
  8. int shmflg ---映射空间权限---0(可读可写)SHM_RDONLY(只读)
  1. int shmdt(const void *shmaddr);
  1. #include <sys/ipc.h>
  2. #include <sys/shm.h>
  3. int shmctl(int shmid, int cmd, struct shmid_ds *buf);

2.4.5 信号量

Created with Raphaël 2.1.2获取key获取semid初始化信号量信号量操作
  1. key_t key=ftok("/",123);
  1. #include <sys/types.h>
  2. #include <sys/ipc.h>
  3. #include <sys/sem.h>
  4. int semget(key_t key, int nsems, int semflg);
函数 参数 说明
返回值 int id 成功返回信号量 ID,失败返回-1
int cmd key_t key 获取唯一 id 的 IPC 键值
int nsems 指出了一个新的信号量集中应该创建的信号量的个数
int semflg IPC_CREAT 如果信号量集在系统内核中不存在,则创建信号量

IPC_EXCL 当和 IPC_CREAT 一同使用时,如果信号量集已经存在,则调用失败。
如果单独使用IPC_CREAT,则semget()要么返回新创建的信号量集的标识符,要么返回系统中已经存在的同样的关键字值的信号量的标识符。
如果 IPC_EXCL和IPC_CREAT一同使用,则要么返回新创建的信号量集的标识符,要么返回-1。
IPC_EXCL单独使用没有意

  1. union semun {
  2. int val; /* Value for SETVAL */
  3. struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
  4. unsigned short *array; /* Array for GETALL, SETALL */
  5. struct seminfo *__buf; /* Buffer for IPC_INFO
  6. (Linux-specific) */
  7. }num;
  8. num.val=1;
  9. int ret=semctl(semid,0,SETVAL,num);//初始化第0个信号量
  1. //原型
  2. int semop(int semid, struct sembuf *sops, unsigned nsops);
  3. //下面是sembuf的成员
  4. unsigned short sem_num; /* semaphore number 操作信号量的下标*/
  5. short sem_op; /* semaphore operation -1获取资源,1释放资源*/
  6. short sem_flg; /* operation flags 0或者IPC_NOWAIT(不阻塞)*/

三.线程

3.1 pthread_create

  1. #include <pthread.h>
  2. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
  3. void *(*start_routine) (void *), void *arg);
函数 参数 说明
pthread_create 返回值 0成功,非0失败(返回失败编号)
pthread_t *thread 保存创建好的线程ID
const pthread_attr_t *attr 线程属性,默认NULL
void *(*start_routine) (void *) 函数指针,线程事务处理函数
void *arg 对线程传递参数(传给线程事物处理函数)

注意:
1. 子线程可以创建子线程
2. 线程内可以将线程事务函数,直接调用.(子线程可以直接调用父线程事务函数,父线程也可以直接调用子线程事务函数)
3. 线程事物函数的void类型参数记得写形参

3.2 线程退出

函数 参数 说明
void pthread_exit(void *retval); 退出本线程
int pthread_cancel(pthread_t thread); thread:需要退出的线程 退出其他线程
int pthread_join(pthread_t thread, void **retval); 缺点:阻塞的 回收线程资源
函数 参数 说明
pthread_join() pthread_t thread 需要回收的线程
void **retval 接收线程的返回值

3.3 线程分离

分离线程不能调用pthread_join回收线程

  1. #include <pthread.h>
  2. int pthread_detach(pthread_t thread);

分离线程后由系统负责回收,而不需要主线程去回收。解决了pthread_join阻塞的问题。

注意:分离的线程只是将子线程的资源回收交给了系统,子线程没有脱离主线程,当主线程杀掉后,子线程也被杀掉了。(原因可能是,主线程杀掉,该进程也就杀掉了,于是进程下的所有线程也就杀掉了)

3.4 线程资源

线程共享的是进程的数据段,而是每个线程都有自己的私有栈。

:保存程序代码分配的空间(malloc一类的函数分配出来的空间)
数据段:保存的是静态变量和全局变量
:保存的是动态变量,局部变量等数据

3.5 线程同步与互斥

3.5.1 工具

3.5.2 互斥锁

  1. #include <pthread.h>
  2. pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//快速互斥锁
  3. pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;//递归互斥锁
  4. pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;//检错互斥锁
  5. int pthread_mutex_init(pthread_mutex_t *mutex,const thread_mutexattr_t
  6. *mutexattr);
函数 参数 说明
pthread_mutex_init pthread_mutex_t *mutex 初始化该锁,需要提前自己定义
const thread_mutexattr_t *mutexattr NULL 为系统默认快速互斥锁
其他填写最上面定义的3种锁
  1. int pthread_mutex_lock(pthread_mutex_t *mutex);
  2. int pthread_mutex_trylock(pthread_mutex_t *mutex);
函数 参数 说明
pthread_mutex_lock pthread_mutex_t *mutex 给初始化后的mutex上锁,阻塞的
pthread_mutex_trylock pthread_mutex_t *mutex 上锁成功返回正确,非阻塞的
若mutex已经上锁,返回错误码
  1. int pthread_mutex_unlock(pthread_mutex_t *mutex);
  1. int pthread_mutex_destroy(pthread_mutex_t *mutex);

3.5.3 信号量

  1. #include <semaphore.h>
  2. int sem_init(sem_t *sem, int pshared, unsigned int value);
函数 参数 说明
sem_init sem_t *sem 要初始化的信号量参数
int pshared 0,同一进程的多个线程共享
非0,共享在两个进程中多个线程共享
unsigned int value 信号量资源数
  1. int sem_wait(sem_t *sem);//
  1. int sem_post(sem_t *sem);
  1. int sem_destory(sem_t *sem);

3.5.4 条件变量

  1. #include <pthread.h>
  2. pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  3. int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
  4. int pthread_cond_broadcast(pthread_cond_t *cond);
  1. int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
  2. int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const
  3. struct timespec *abstime);
  1. int pthread_cond_signal(pthread_cond_t *cond);
  1. int pthread_cond_destroy(pthread_cond_t *cond);

3.5.5 线程池

  1. struct rackNode{
  2. void *(*tack_func)(void *);
  3. struct tackNode *next;
  4. }
  1. 创建多个线程,用条件变量阻塞。
  2. 将线程需要执行的函数,以指针的形式保存在任务链表中
  3. 每次激活线程的时候,线程去任务表中取一个任务(取一个链表中的函数)同时,从链表中移除该节点,然后执行该节点的函数,然后free该节点。

注意:不能在线程中使用同一把互斥锁。

示例模型代码:

  1. #include<stdio.h>
  2. #include<stdlib.h>
  3. #include<stdbool.h>
  4. #include<string.h>
  5. #include<fcntl.h>
  6. #include<unistd.h>
  7. #include<pthread.h>
  8. typedef struct tackNode
  9. {
  10. void (*tack_fun)(void);
  11. int num;
  12. struct tackNode *next;
  13. }tackNode;
  14. tackNode *create_tack(void (*tack_fun)(void))
  15. {
  16. tackNode *tack = (tackNode*)malloc(sizeof(tackNode));
  17. if(tack == NULL)return NULL;
  18. tack->tack_fun = tack_fun;
  19. tack->next = NULL;
  20. return tack;
  21. }
  22. pthread_cond_t cont;
  23. void *run(void *arg)
  24. {
  25. tackNode *tackpool = (tackNode*)arg;
  26. pthread_mutex_t mutex;
  27. pthread_mutex_init(&mutex, NULL);
  28. while(1)
  29. {
  30. //挂起
  31. pthread_cond_wait(&cont, &mutex);
  32. printf("-------\n");
  33. tackNode *ptack = tackpool->next;
  34. if(ptack == NULL)continue;
  35. tackpool->next = ptack->next;
  36. printf("这是第%d个任务\n", ptack->num);
  37. ptack->tack_fun();
  38. }
  39. }
  40. void tack(void)
  41. {
  42. printf("tack--%d-start\n", pthread_self());
  43. sleep(10);printf("=====================\n");
  44. printf("tack--%d--end\n", pthread_self());
  45. }
  46. void add_tack(tackNode *tackpool, void (*tack)(void), int num)
  47. {
  48. tackNode *new = create_tack(tack);
  49. new->num = num;
  50. new->next = tackpool->next;
  51. tackpool->next = new;
  52. }
  53. int main(void)
  54. {
  55. pthread_cond_init(&cont, NULL);
  56. tackNode *tackpool = create_tack(NULL);
  57. if(tackpool == NULL) perror("create fail"),exit(-1);
  58. int i=0, ret =0;
  59. pthread_t id = 0;
  60. for(i=0; i<10 ; i++)
  61. {
  62. ret = pthread_create(&id , NULL, run,(void *)tackpool);
  63. }
  64. int num =0;
  65. while(1)
  66. {
  67. sleep(1);
  68. add_tack(tackpool, tack, num++);
  69. pthread_cond_signal(&cont);
  70. if(num % 20 == 0)
  71. {
  72. sleep(30);
  73. }
  74. }
  75. while(1);
  76. return 0;
  77. }

四.进程与线程的关系

区别:


五.文件锁

fcntl上锁:

  1. #include <unistd.h>
  2. #include <fcntl.h>
  3. int fcntl(int fd, /*上锁的文件*/
  4. int cmd,/*命令*/
  5. ... /* arg flock结构体*/
  6. );
  7. //结构体
  8. struct flock {
  9. ...
  10. short l_type; /* Type of lock: F_RDLCK,
  11. F_WRLCK, F_UNLCK */
  12. short l_whence; /* How to interpret l_start:
  13. SEEK_SET, SEEK_CUR, SEEK_END */
  14. off_t l_start; /* Starting offset for lock */
  15. off_t l_len; /* Number of bytes to lock */
  16. pid_t l_pid; /* PID of process blocking our lock
  17. (F_GETLK only) */
  18. ...
  19. };

flock上锁:

  1. #include <sys/file.h>
  2. int flock(int fd, int operation);

参数:

  • int fd:文件描述符
  • int operation:上锁操作
    • LOCK_SH 获取共享锁
    • LOCK_EX 获取互斥锁(无法获取时会阻塞)
    • LOCK_NU 解锁
    • LOCK_NB

优缺点:
简单,但是只能锁整个文件,不能锁一段文本

六.系统日志

  1. #include <syslog.h>
  2. void openlog(const char *ident, int option, int facility);
  3. void syslog(int priority, const char *format, ...);
  4. //例如:syslog(LOG_INFO, "%s", "fopen fail");
  5. void closelog(void);
函数 参数 说明
openlog() const char *ident 身份(标志),传入表明自己身份的字符串
int option LOG_CONS--写日志到系统如果出错就会写入系统控制台
LOG_NDELAY --不延时
LOG_PERROR---将消息发送给标准出错,并且发送给系统日志服务
LOG_PID---每一条消息中添加进程号
int facility 日志类型/var/log
syslog() int priority 消息类型(man syslog 查看)
const char *format 消息的格式如:"%s"
... 消息
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注