管道:
无名管道(仅适用于亲缘进程)
1、创建管道 利用 pipe 函数, 在创建前定义一个整型数组,
例:int fd[2];
pipe(fd); // fd[0]读描述符,fd[1]写描述符
2、写
例:write(fd[1],"hello",5);
3、读
例:read(fd[0], buf, sizeof(buf));
有名管道
1、创建管道 利用mkfifo 函数
例:mkfifo("/home/china/fifo1", 0644);
2、打开管道文件 返回文件标识符
例:int fd = open("/home/china/fifo1", O_RDWR);
3、写
例:write(fd, buf, strlen(buf));
4、读
例:read(fd,buf,sizeof(buf)); //等待 管道有数据可读
信号量:
无名信号量:
- 在所有线程都能访问到的地方定义一个 sem_t 类型的变量
例:sem_t sem;
2、对无名信号量进行初始化,利用sem_init 函数
函数原型:int sem_init(sem_t *sem, int pshared, unsigned int value);
- 对信号量进行P操作 利用函数 sem_wait 、sem_trywait
函数原型:int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
- V操作 利用sem_post函数
函数原型:int sem_post(sem_t *sem);
- 不在需要时,需要销毁 利用 sem_destroy 函数
函数原型:int sem_destroy(sem_t *sem);
有名信号量
1、创建或打开一个有名信号量 利用 sem_open 函数
例:sem_t * fd_sem = sem_open("/my_sem_name", O_CREAT , 0644 , 0 );
2、P 操作 利用 sem_wait 函数
例:sem_wait(fd_sem);
3、V操作
例:sem_post(fd_sem);
4、关闭信号量
例:sem_close(fd_sem);
5、删除信号量
例:sem_unlock(fd_sem);
消息队列:
1、创建一个唯一键值 key ,利用 ftok 函数
例:key_t key = ftok("/home/china",'S');
2、创建或打开消息队列 , 利用 msgget 函数, 创建成功返回队列ID(标识符)
例:int msqid = msgget(key, IPC_CREAT|0644);
3、定义一个消息队列的结构体并定义一个结构体变量 用于发送和接收消息时使用
例:struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[100]; /* message data */};
struct msgbuf msg1;
msg1.mtype = 1; //消息的类型
4、向消息队列发送消息 利用函数 msgsnd
例:msgsnd(msqid, &msg1, strlen(msg1.mtext), 0);
5、接收消息 返回实际接收的字节数
例:int n = msgrcv(msqid, &msg1, strlen(msg1.mtext), 1, 0);
共享内存:
1、创建一个唯一键值 key ,利用 ftok 函数
例:key_t key = ftok("/home/china",'S');
2、创建一个共享内存 , 利用 shmget 函数,创建成功返回共享内存标识符
例:int shmid = shmget(key, 100, IPC_CREAT|0644);
注意:为什么已经有一个key来标识共享内存,还想要共享内存标识符来标识呢?
因为key是内核级别的,供内核标识,而共享内存标识符是用户级别,为了供用户标识
3、共享内存关联进程,利用 shmat 函数,创建成功返回映射到进程地址共享空间的开始地址
例:char *p = shmat(shmid, NULL, 0);
4、删除共享内存与进程的关联 利用shmdt 函数
例:shmdt(p);
注意:IPC(进程间通信)资源生命周期不随进程,而是随内核,在进程结束后,共享内存还在,在第二次执行时会报错,所以,shmget 创建的共享内存要在使用结束后释放掉,不然内存会泄露。
5、释放共享内存 利用 shmctl 函数 (一般为服务端释放)
例:int sh = shmctl(shmid, IPC_RMID, NULL);
线程:
- 先定义线程id
例:pthread_t tid1;
- 创建线程 利用 pthread_create 函数,创建线程同时调用线程函数
例:pthread_create(&tid1, NULL,pthread1, &tid1);
- 线程退出 利用 pthread_exit 或其他线程调用 pthread_cancel
例:void pthread_exit(void *retval);
int pthread_cancel(pthread_t thread);
- 等待回收线程id 利用函数 pthread_join
例:pthread_join(tid1, NULL);
线程之间的同步 —信号量、线程互斥锁
线程互斥锁:
- 声明并初始化线程互斥锁
例:pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
或:int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
2、p/v操作
例:pthread_mutex_lock(&mutex1);
pthread_mutex_unlock(&mutex1);
3、销毁互斥锁
例:pthread_mutex_destroy(&mutex1);
条件变量:
1、声明并初始化一个条件变量
例:pthread_cond_t hasApple = PTHREAD_COND_INITIALIZER;
或:int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
2、等待一个条件变量 可以理解为让线程睡眠
例:pthread_cond_wait(&hasEmpty, &lock);
3、唤醒线程
例:pthread_cond_signal(&hasEmpty);
线程池
线程池就是创建一个线程的集合,再创建一个任务的队列,任务列中任务的执行依靠线程池的的线程,当任务执行完后归还线程回去等待下一任务使用,可避免线程频繁的创建和销毁
- 创建任务队列
- 创建线程池
- 初始化线程池
- 给任务队列中添加任务
- 调用任务执行
- 销毁线程池