文章目录
线程的信号量
原理简介:
线程的信号量和进程的类似,维护一个sem_t类型(本质是一个int类型的)的信号量,不同线程通过判断信号量的值,来决定是否进行继续运行,从而控制线程运行的先后顺序。比如信号量初始化成0,线程1调用sem_wait阻塞住,等待线程2调用sem_post将限号量增加之后,线程1被唤醒,从而实现线程1、2执行的顺序。
使用流程:
- sem_init初始化信号量
- sem_post增加信号量
- sem_wait判断并减少信号量
初始化信号量:sem_init
sem_init用于初始化信号量的初始值和作用范围。
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
Link with -pthread;
sem: 需要被初始化的信号量对象;
value: 初始值;
pshared: 1)0,表示信号量线程共享,多线程可以共同操作该信号量,要求sem变量的作用域能被多个线程访问到;2)非0,表示信号量进程共享,多进程可以共同操作该信号量,如果是父子进程,要求sem变量的作用域能被多个进程访问到,若父子进程,则可以直接访问,若没有关系的进程,那么sem要在共享内存中创建;
返回值: 成功,返回0;失败,返回-1,并置上errno;
减少信号量:sem_wait
sem_wait函数判断信号量是否大于0,如果大于0,则将信号量减一,并且立即返回,如果小于等于0,就阻塞在该函数,直到信号量大于0。
#include <semaphore.h>
int sem_wait(sem_t *sem);
sem: 待操作的信号量;
返回值: 成功,返回0;失败,返回-1,并置上errno
增加信号量:sem_post
sem_post用于给信号量加1
#include <semaphore.h>
int sem_post(sem_t *sem);
sem: 待操作的信号量;
返回值: 成功,返回0;失败,返回-1,并置上errno
删除信号量:sem_destroy
#include <semaphore.h>
int sem_destroy(sem_t *sem);
sem: 待操作的信号量;
返回值: 成功,返回0;失败,返回-1,并置上errno
代码示例
线程1先被创建,但是阻塞在信号量上,线程2后被创建,被运行后将信号量增加,然后线程1识别到信号量大于零,才执行后面的步骤。
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
sem_t sem;
void * func1(void *arg)
{
int ret;
ret = sem_wait(&sem);
if (ret != 0) {
perror("sem_wait: ");
return NULL;
}
printf("%s: pthread id: %ul\n", __func__, pthread_self());
}
void * func2(void *arg)
{
int ret;
printf("%s: pthread id: %ul\n", __func__, pthread_self());
ret = sem_post(&sem);
if (ret != 0) {
perror("sem_post: ");
return NULL;
}
}
int
main(int argc, char **argv)
{
int ret;
pthread_t p1, p2;
ret = sem_init(&sem, 0, 0);
if (ret < 0) {
perror("sem_init: ");
return -1;
}
ret = pthread_create(&p1, NULL, &func1, NULL);
if (ret != 0) {
perror("pthread_create: ");
return -1;
}
sleep(5);
ret = pthread_create(&p2, NULL, &func2, NULL);
if (ret != 0) {
perror("pthread_create: ");
return -1;
}
sleep(1);
return 0;
}
线程的互斥量
原理简介:
- 互斥量底层也是通过锁实现的,第一个线程访问互斥量的时候对互斥量加锁,后续线程加锁互斥量的时候会被阻塞,直到锁被释放
- 互斥量在POSIX中定义
- 互斥量是一种特殊的信号量,信号量是一个int数值,可以随意大小,互斥量只有0和1
使用流程:
- 初始化互斥量
- 锁住互斥量
- 解锁互斥量
- 销毁互斥量
初始化互斥量:pthread_mutex_init
互斥量用之前必须初始化:
//初始化方法1:使用默认属性,必须在定义的时候初始化,不可以先定义后初始化
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//初始化方法2:
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex,
const pthread_mutexattr_t *restrict attr);
mutex: 待初始化的互斥量;
attr: 参数,可以直接使用NULL;
返回值: 成功,返回0,失败,返回非0,并置上errno
锁住互斥量:pthread_mutex_lock
#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t *mutex);
mutex: 待锁住的互斥量;
返回值: 成功,返回0,失败,返回非0,并置上errno
解锁互斥量:pthread_mutex_unlock
#include <pthread.h>
int pthread_mutex_unlock(pthread_mutex_t *mutex);
mutex: 待解锁的互斥量;
返回值: 成功,返回0,失败,返回非0,并置上errno;
销毁互斥量:pthread_mutex_destroy
互斥量用完了之后要释放
#include <pthread.h>
int pthread_mutex_destroy(pthread_mutex_t *mutex);
mutex: 待销毁的互斥量;
返回值: 成功,返回0,失败,返回非0,并置上errno;
代码示例
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * func1(void *arg)
{
int ret;
ret = pthread_mutex_lock(&mutex);
if (ret != 0){
perror("pthread_mutex_lock: ");
return NULL;
}
printf("%s: pthread id: %ul\n", __func__, pthread_self());
pthread_mutex_destroy(&mutex);
}
void * func2(void *arg)
{
int ret;
printf("%s: pthread id: %ul\n", __func__, pthread_self());
}
int
main(int argc, char **argv)
{
int ret;
pthread_t p1, p2;
//ret = pthread_mutex_init(&mutex, NULL);
//if (ret != 0) {
// perror("pthread_mutex_init: ");
// return -1;
//}
ret = pthread_mutex_lock(&mutex);
if (ret != 0){
perror("pthread_mutex_lock: ");
return -1;
}
ret = pthread_create(&p1, NULL, &func1, NULL);
if (ret != 0) {
perror("pthread_create: ");
return -1;
}
sleep(5);
ret = pthread_create(&p2, NULL, &func2, NULL);
if (ret != 0) {
perror("pthread_create: ");
return -1;
}
sleep(1);
ret = pthread_mutex_unlock(&mutex);
if (ret != 0){
perror("pthread_mutex_lock: ");
return -1;
}
sleep(1);
return 0;
}