@rfish
2015-08-25T08:33:08.000000Z
字数 10736
阅读 2729
培训
主要状态:
其他状态:
关于sleep( ):
#include <unistd.h>
+---------+ +---------+| Stack栈 | | Stack栈 |+---------+ +---------+| Heep | fork() | Heep |+---------+ +--------> +---------+| DATA | | DATA |+---------+ +---------+| Code | | Code |+---------+ +---------+
运行的状态,程序已经执行的位置。)
pid_t fork();//返回生成的子进程的pid(数据类型为pid_t,也是int)
说明:
在父进程中fork()返回的是子进程ID号,在fork出来的子进程中返回的是0。返回值:
- <0:创建失败
- >0:当前运行在父进程
- =0:当前运行在子进程
其他创建进程的函数:
exec 函数族
+---------+| Stack栈 |+---------+| deep |+---------+| DATA |+---------+ exec函数族| | -----------+| | || Code | |根据exec函数族的程序路径参数,将代码覆盖掉。| | || | <----------++---------+会将原先进程的代码全部覆盖
_exit( )
系统调用函数,直接退出,不做任何其他处理。
关于缓冲:
printf("qwerqreqwerqre");printf("qwerqreqwerqre\n");僵尸进程:
子进程退出,父进程还在运行且没有回收子进程的资源(子进程复制的资源还在保留)
避免进程僵尸:
#include<sys/types.h>#include<sys/wait.h>int status;//用以保存子进程的状态pid_t pid=wait(&status);//wait可以接收子进程的exit的状态,也可以回收子进程的资源WEXITSTATUS(stata);//解析子进程退出返回的状态。
| 方式 | 函数 | 说明 |
|---|---|---|
| 文件 | 对同一文件读写 | |
| mmap | mmap() |
父子间通信,MAP_SHARED |
| 有名管道 | mkfifo(); |
同一系统任意进程间通信,有实际的管道文件 |
| 无名管道 | pipe(); |
只适用于父子间通信,没有实际的管道文件 |
| 信号 | kill()、alarm()、raise() |
signal()拦截信号 |
| IPC 消息队列 | ftok()、msgget、msgsnd、msgrcv、msgctl |
|
| IPC 共享内存 | ftok()、shmget、shmat、shmdt、msgctl |
|
| IPC 信号量 | semget、semctl、semop |
semget 返回semid |
当子进程退出的时候会发送SIGCHLD信号给父进程,父进程可接收该信号,调用wait回收子进程
发送信号函数特性:
- kill
- 可以发给任何进程
- alarm
- 只能发给自己只能是SIGALRM信号
- 可以设置发送定时
- 一次调用只能发送一次
- raise
- 只能发给本进程
- 可以定制发送的信号
- 立即发送
pause();函数会暂停程序,当接收到SIGCONT信号才会继续运行。
适用:同一系统的任意进程
#include <sys/types.h>#include <sys/stat.h>int mkfifo(const char *pathname, mode_t mode);//pathname:要创建的管道文件路径//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).
#include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);//proj_id只有低八位有效0-255
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>int msgget(key_t key, int msgflg);//返回队列描述符
| 参数 | 值 | 说明 |
|---|---|---|
| int msgflg | IPC_CREAT | 创建队列 |
| IPC_EXCL | 如果队列存在就会出错---errno 是否等于EEXIST | |
| 与权限相或例如: IPC_CREAT|0777 |
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>struct msgbuf {long mtype; /* message type, must be > 0 */char mtext[1]; /* message data */char m[1000];};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 |
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
| 函数 | 参数 | 说明 |
|---|---|---|
| msgrcv() | 返回值 | -1失败, 接收字节数(成功) |
| void *msgp | 接收消息结构地址 | |
| size_t msgsz | 接收消息正文长度 | |
| long msgtyp | 接收消息类型(编号),msgtyp相同才接收 | |
| int msgflg | 0(接收如果没有数据就会阻塞) IPC_NOWAIT |
#include <sys/types.h>#include <sys/ipc.h>#include <sys/msg.h>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 |
#include <sys/types.h>#include <sys/ipc.h>key_t ftok(const char *pathname, int proj_id);//proj_id只有低八位有效0-255
#include <sys/ipc.h>#include <sys/shm.h>int shmget(key_t key, size_t size, int shmflg);返回值:int ---获取到的共享内存id(描述符)参数:key_t key -- ipc键值size_t size---共享内存空间大小(一般一页整数倍)getpagesizeint shmflg----IPC_CREAT创建---权限
#include <sys/types.h>#include <sys/shm.h>void *shmat(int shmid, const void *shmaddr, int shmflg);返回值:成功(映射到用户空间的首地址) 失败((void*)-1)参数:int shmid----共享内存idconst void *shmaddr---用户空间地址与内存空间映射用(一般NULL系统自动分配)int shmflg ---映射空间权限---0(可读可写)SHM_RDONLY(只读)
int shmdt(const void *shmaddr);
#include <sys/ipc.h>#include <sys/shm.h>int shmctl(int shmid, int cmd, struct shmid_ds *buf);
key_t key=ftok("/",123);
#include <sys/types.h>#include <sys/ipc.h>#include <sys/sem.h>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单独使用没有意
union semun {int val; /* Value for SETVAL */struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */unsigned short *array; /* Array for GETALL, SETALL */struct seminfo *__buf; /* Buffer for IPC_INFO(Linux-specific) */}num;num.val=1;int ret=semctl(semid,0,SETVAL,num);//初始化第0个信号量
semop)
//原型int semop(int semid, struct sembuf *sops, unsigned nsops);//下面是sembuf的成员unsigned short sem_num; /* semaphore number 操作信号量的下标*/short sem_op; /* semaphore operation -1获取资源,1释放资源*/short sem_flg; /* operation flags 0或者IPC_NOWAIT(不阻塞)*/
#include <pthread.h>int pthread_create(pthread_t *thread, const pthread_attr_t *attr,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类型参数记得写形参
| 函数 | 参数 | 说明 |
|---|---|---|
| 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 | 接收线程的返回值 |
分离线程不能调用pthread_join回收线程
#include <pthread.h>int pthread_detach(pthread_t thread);
分离线程后由系统负责回收,而不需要主线程去回收。解决了pthread_join阻塞的问题。
注意:分离的线程只是将子线程的资源回收交给了系统,子线程没有脱离主线程,当主线程杀掉后,子线程也被杀掉了。(原因可能是,主线程杀掉,该进程也就杀掉了,于是进程下的所有线程也就杀掉了)
线程共享的是进程的堆和数据段,而栈是每个线程都有自己的私有栈。
堆:保存程序代码分配的空间(malloc一类的函数分配出来的空间)
数据段:保存的是静态变量和全局变量
栈:保存的是动态变量,局部变量等数据
#include <pthread.h>pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;//快速互斥锁pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;//递归互斥锁pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;//检错互斥锁int pthread_mutex_init(pthread_mutex_t *mutex,const thread_mutexattr_t*mutexattr);
| 函数 | 参数 | 说明 |
|---|---|---|
| pthread_mutex_init | pthread_mutex_t *mutex | 初始化该锁,需要提前自己定义 |
| const thread_mutexattr_t *mutexattr | NULL 为系统默认快速互斥锁 | |
| 其他填写最上面定义的3种锁 |
int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);
| 函数 | 参数 | 说明 |
|---|---|---|
| pthread_mutex_lock | pthread_mutex_t *mutex | 给初始化后的mutex上锁,阻塞的 |
| pthread_mutex_trylock | pthread_mutex_t *mutex | 上锁成功返回正确,非阻塞的 |
| 若mutex已经上锁,返回错误码 |
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
#include <semaphore.h>int sem_init(sem_t *sem, int pshared, unsigned int value);
| 函数 | 参数 | 说明 |
|---|---|---|
| sem_init | sem_t *sem | 要初始化的信号量参数 |
| int pshared | 0,同一进程的多个线程共享 | |
| 非0,共享在两个进程中多个线程共享 | ||
| unsigned int value | 信号量资源数 |
int sem_wait(sem_t *sem);//
int sem_post(sem_t *sem);
int sem_destory(sem_t *sem);
#include <pthread.h>pthread_cond_t cond = PTHREAD_COND_INITIALIZER;int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, conststruct timespec *abstime);
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_destroy(pthread_cond_t *cond);
struct rackNode{void *(*tack_func)(void *);struct tackNode *next;}
- 创建多个线程,用条件变量阻塞。
- 将线程需要执行的函数,以指针的形式保存在任务链表中
- 每次激活线程的时候,线程去任务表中取一个任务(取一个链表中的函数)同时,从链表中
移除该节点,然后执行该节点的函数,然后free该节点。注意:不能在线程中使用同一把互斥锁。
示例模型代码:
#include<stdio.h>#include<stdlib.h>#include<stdbool.h>#include<string.h>#include<fcntl.h>#include<unistd.h>#include<pthread.h>typedef struct tackNode{void (*tack_fun)(void);int num;struct tackNode *next;}tackNode;tackNode *create_tack(void (*tack_fun)(void)){tackNode *tack = (tackNode*)malloc(sizeof(tackNode));if(tack == NULL)return NULL;tack->tack_fun = tack_fun;tack->next = NULL;return tack;}pthread_cond_t cont;void *run(void *arg){tackNode *tackpool = (tackNode*)arg;pthread_mutex_t mutex;pthread_mutex_init(&mutex, NULL);while(1){//挂起pthread_cond_wait(&cont, &mutex);printf("-------\n");tackNode *ptack = tackpool->next;if(ptack == NULL)continue;tackpool->next = ptack->next;printf("这是第%d个任务\n", ptack->num);ptack->tack_fun();}}void tack(void){printf("tack--%d-start\n", pthread_self());sleep(10);printf("=====================\n");printf("tack--%d--end\n", pthread_self());}void add_tack(tackNode *tackpool, void (*tack)(void), int num){tackNode *new = create_tack(tack);new->num = num;new->next = tackpool->next;tackpool->next = new;}int main(void){pthread_cond_init(&cont, NULL);tackNode *tackpool = create_tack(NULL);if(tackpool == NULL) perror("create fail"),exit(-1);int i=0, ret =0;pthread_t id = 0;for(i=0; i<10 ; i++){ret = pthread_create(&id , NULL, run,(void *)tackpool);}int num =0;while(1){sleep(1);add_tack(tackpool, tack, num++);pthread_cond_signal(&cont);if(num % 20 == 0){sleep(30);}}while(1);return 0;}
区别:
fcntl上锁:
#include <unistd.h>#include <fcntl.h>int fcntl(int fd, /*上锁的文件*/int cmd,/*命令*/... /* arg flock结构体*/);//结构体struct flock {...short l_type; /* Type of lock: F_RDLCK,F_WRLCK, F_UNLCK */short l_whence; /* How to interpret l_start:SEEK_SET, SEEK_CUR, SEEK_END */off_t l_start; /* Starting offset for lock */off_t l_len; /* Number of bytes to lock */pid_t l_pid; /* PID of process blocking our lock(F_GETLK only) */...};
flock上锁:
#include <sys/file.h>int flock(int fd, int operation);
参数:
- int fd:文件描述符
- int operation:上锁操作
- LOCK_SH 获取共享锁
- LOCK_EX 获取互斥锁(无法获取时会阻塞)
- LOCK_NU 解锁
- LOCK_NB
优缺点:
简单,但是只能锁整个文件,不能锁一段文本
#include <syslog.h>void openlog(const char *ident, int option, int facility);void syslog(int priority, const char *format, ...);//例如:syslog(LOG_INFO, "%s", "fopen fail");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" | |
| ... | 消息 |