@rfish
2015-08-25T08:33:08.000000Z
字数 10736
阅读 2437
培训
主要状态:
其他状态:
关于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---共享内存空间大小(一般一页整数倍)getpagesize
int shmflg----IPC_CREAT创建---权限
#include <sys/types.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功(映射到用户空间的首地址) 失败((void*)-1)
参数:
int shmid----共享内存id
const 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, const
struct 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" | |
... | 消息 |