一、进程通信
1.管道
(1)无名管道
所用函数:
int pipe(int pipefd[2]);
返回值:成功0,失败-1
参数:数组
代码示例:
int p[2];
if(-1 == pipe(p))
{
perror("pipe");
exit(-1);
}
在进程中具体使用方式如下:
else if(0 == pid) //子进程
{
close(p[1]);//关闭写
char buf[20];
read(p[0], buf, sizeof(buf));
puts(buf);
exit(0);
}
else //父进程
{
close(p[0]);//关闭读
char buf[20];
gets(buf);
write(p[1], buf, sizeof(buf));
exit(0);
wait(NULL);
}
(2)有名管道
半双工 命令;mkfifo
所用函数:
int mkfifo(const char * pathname,mode_t mode);
返回值:成功0 失败-1;
参数:pathname 管道权限
mode 文件权限
代码示例:
write.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
int main(int argc, char *argv[])
{
if(-1 == mkfifo("fifo", 0666))
{
perror("mkfifo");
exit(-1);
}
int fd = open("fifo", O_WRONLY);
if(-1 == fd)
{
perror("open");
exit(-1);
}
char buf[20];
while(1)
{
gets(buf);
write(fd, buf, sizeof(buf));
}
}
read.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int fd = open("fifo", O_RDONLY);
if(-1 == fd)
{
perror("open");
}
char buf[20];
while(1)
{
read(fd, buf, sizeof(buf));
puts(buf);
}
}
编写使用时记得把fifo文件删除
2.信号
所用函数:
int raise(int sig);//给自己发送信号
返回值:成功0 失败-1;
参数:sig :信号
int kill(pid_t pid, int sig);//给别人发送信号
返回值:成功0 失败-1;
参数:
- pid 传过来的pid
- sig:信号
unsigned int alarm(unsigned int seconds);
返回值:如果第一次使用,返回0,如果不是第一次,返回上一次计数剩余时间
参数:seconds:秒数
typedef void (*sighandler_t)(int);
(void*)-1 == sighandler_t signal(int signum, sighandler_t handler); //处理捕获函数
返回值:失败NULL,成功处理函数首地址
参数:
- signum:处理信号
- handler:处理函数(SIG_IGN:忽略 SIG_DFL:缺省)
3.IPC
(1)共享内存
1.创建共享内存
所用函数:
int shmget(key_t key, size_t size, int shmflg);
返回值:成功返回id 失败-1
参数:
- key:key值
- size:共享内存大小
- shmflg:权限
key_t ftok(const char *pathname, int proj_id);
返回值:成功返回key值,失败返回-1
参数:
- pathname:文件路径
- proj_id:通常会给一个字符
代码示例:
key_t key = ftok("1.txt", 'A');
if(-1 == key)
{
perror("ftok");
exit(-1);
}
printf("key=%X\n", key);
//打开/创建一个ipc对象获取id
int shmid = shmget(key, 1024, IPC_CREAT);
if(-1 == shmid)
{
perror("shmget");
exit(-1);
}
2.映射
所用函数:
void *shmat(int shmid, const void *shmaddr, int shmflg);
返回值:成功返回映射后的用户地址,失败返回-1
参数:
- shmid: 共享内存id
- shmaddr:映射的位置,一般为NULL,自动分配
- shmflg:打开方式,通常用SHM_RDONLY,默认0
注意!!!运行时需要加sudo
代码示例:
void*addr = NULL;
addr = shmat(shmid, NULL, 0);
if((void*)-1 == addr)
{
perror("shmat");
exit(-1);
}
3.取消映射
所用函数:
int shmdt(const void *shmaddr);
返回值:成功0,错误-1
参数: 映射的首地址
代码示例:
if(-1 == shmdt(addr))
{
perror("shmdt");
exit(-1);
}
4.删除共享内存
所用函数:
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:成功0,错误-1
参数:
- shmid :共享内存id
- cmd :IPC_SET IPC_STAT //需要传递第三个参数
IPC_RMID 删除,不用第三个参数
代码示例:
if(-1 == shmctl(shmid, IPC_RMID, NULL))
{
perror("shmctl");
exit(-1);
}
(2)信号灯集
1.创建信号灯集
所用函数:
int semget(key_t key, int nsems, int semflg);
返回值:成功返回id 失败-1
参数:
- key:ftok的值
- nsems::灯集个数
- semflags:权限 IPC_CREAT|0600
代码示例:
int sem_id = semget(key, 2, IPC_CREAT|0600);
if(-1 == sem_id)
{
perror("sem_get");
return -1;
}
2.给信号灯初值
所用函数:
int semctl(int semid, int semnum, int cmd, union buf);
返回值:失败返回-1
参数:
- semid:信号灯集的id
- semnum:信号灯编号
- cmd:执行操作
- buf:相关共用体
代码示例:
union semun sun;
sun.val = 0;
if(-1 == semctl(sem_id, R, SETVAL, sun))
{
perror("setval");
return -1;
}
sun.val = 1;
if(-1 == semctl(sem_id, W, SETVAL, sun))
{
perror("setval");
return -1;
}
3.生产/消费
所用函数:
int semop(int semid, struct sembuf *sops, size_t nsops);
返回值:成功0,错误-1
参数:
- semid:信号灯id
- sembuf:操作的结构体首地址
- nsops:操作的信号灯个数
代码示例:
//消费
int P(int sem_id, int semnum)
{
struct sembuf sem_val;
sem_val.sem_num = semnum; //第几个信号灯
sem_val.sem_op = -1; //消费
sem_val.sem_flg = 0;
if(-1 == semop(sem_id, &sem_val, 1))
{
perror("semop");
return -1;
}
return 0;
}
//生产
int V(int sem_id, int semnum)
{
struct sembuf sem_val;
sem_val.sem_num = semnum; //第几个信号灯
sem_val.sem_op = 1; //生产
sem_val.sem_flg = 0;
if(-1 == semop(sem_id, &sem_val, 1))
{
perror("semop");
return -1;
}
return 0;
}
(3)消息队列
1.创建消息队列
所用函数:
int msgget(key_t key, int msgflg);
返回值:消息队列id,失败-1
参数:
- key:key值
- msgflg:权限
代码示例:
int msgid = msgget(key, IPC_CREAT|0600);
if(-1 == msgid)
{
perror("msgget");
exit(-1);
}
2.发送消息/接收消息
所用函数:
第一种:
int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);
返回值:成功0,失败-1
参数:
- msqid:消息队列id
- msgp:消息 结构体首地址
- msgsz:消息大小(不包含type)
- msgflg:权限,默认0
代码示例:
struct msgbuf buf;
buf.type = 100;
strcpy(buf.buf, "hello");
if(-1 == msgsnd(msgid, &buf, sizeof(buf.buf), 0))
{
perror("msgsdn");
exit(-1);
}
第二种:
ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp,int msgflg);
返回值:成功0,失败-1
参数:
- msqid:消息队列id
- msgp:消息 结构体首地址
- msgsz:消息大小(不包含type)
- msgtyp:消息的编号
- msgflg:权限,默认0
代码示例:
struct msgbuf buf;
int ret = msgrcv(msgid, &buf, sizeof(buf.buf), 100, 0);
if(-1 == ret)
{
perror("msgrcv");
exit(-1);
}
二、线程通信
1.同步
按照一定的顺序去完成某一件事情
信号量
1.创建信号量,并初始化
所用函数:
int sem_init(sem_t *sem, int pshared, unsigned int value);
返回值:成功0,失败非0
参数:
- sem:信号量
- pshared:0共享
- value:初值
代码示例:
if(0 != sem_init(&read, 0, 0))
{
perror("seminnit");
exit(-1);
}
if(0 != sem_init(&write, 0, 1))
{
perror("seminnit");
exit(-1);
}
2.消费
所用函数:
int sem_wait(sem_t *sem);
返回值:成功0,失败非0
参数:sem:信号量
3.生产
所用函数:
int sem_post(sem_t *sem);
返回值:成功0,失败非0
参数:sem:信号量
代码示例:
while(1)
{
sem_wait(&read);
puts(buf);
sem_post(&write);
}
2.互斥
某一线程正在使用某个资源时,那么其他线程就不能使用该线程
互斥锁
1.创建锁,并且初始化
所用函数
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutex‐
attr_t *mutexattr);
返回值:成功0;失败非0
参数
- mutex:锁
- mutexattr:属性 默认属性NULL
代码示例:
pthread_mutex_t mutex;
if(0 != pthread_mutex_init(&mutex, NULL))
{
perror("mutex_init");
pthread_exit(NULL);
}
2.上锁
所用函数
int pthread_mutex_lock(pthread_mutex_t *mutex);
返回值:成功0,失败非0
参数:mutex :锁
3.解锁
所用函数
int pthread_mutex_unlock(pthread_mutex_t *mutex);
返回值:成功0,失败非0
参数:mutex :锁
代码示例:
while(1)
{
pthread_mutex_lock(&mutex);
if(a == b)
{
printf("hello a=%d b=%d\n", a, b);
}
pthread_mutex_unlock(&mutex);
}
4.摧毁锁
所用函数
int pthread_mutex_destroy(pthread_mutex_t *mutex);
返回值:成功0失败非0
参数:mutex:锁