POSIX
信号量
POSIX
没有元素这个概念相比于SYSTEM-V
更简洁,POSIX
不一定适用老版本;二者都是系统范畴,都需要手动删除,POSIX
相关函数属于线程库,所有编译时需要末尾加上-lpthread
选项
POSIX
-
POSIX
有名信号量-
主要用于进程间通信
-
创建成功后,器特殊文件存放路径:
/dev/shm/
-
-
POSIX
无名信号量(属于进程间,随着进程的消亡而消失)-
主要用于线程间通信
-
//无名信号量用于线程间同步和互斥
#include "head.h"
sem_t data;
sem_t space;
void* routine(void* arg)
{
char* num = (char*)arg;
while(1)
{
sem_wait(&data);
printf("routine: %s\n", num);
sem_post(&space);
}
}
int main()
{
char str[100];
// 第一个参数:创建成功后返回的信号量标识符
// 第二参数: 0代表线程间通信
// 第三个参数:当前信号量的初始值
sem_init(&data, 0, 0);
sem_init(&space, 0, 1);
pthread_t tid;
pthread_create(&tid, NULL, routine, str);
while(1)
{
sem_wait(&space);
bzero(str, sizeof(str));
fgets(str, sizeof(str), stdin);
sem_wait(&data);
}
return 0;
}
锁与条件变量
//用于验证互斥锁读写锁与条件变量(用于解决互斥锁的死锁问题)
// 定义一个共享资源,通过条件变量控制访问
int balance = 0;
// 条件变量通常需要结合互斥锁使用
pthread_mutex_t m;
// 条件变量是用于解决互斥锁使用过程中可能出现的死锁
pthread_cond_t v;
//线程函数 -- 相当于兄弟姐妹
void* routine(void* arg)
{
//对共享资源访问时需要加锁、解锁操作
pthread_mutex_lock(&m);
while(balance < 100)
{
// 卡里没钱则进入条件等待队列,进入队列时,条件变量会自动执行解锁操作,这是条件变量底层已经封装好了,无需手动操作
pthread_cond_wait( &v, &m);
}
fprintf(stderr, "[%lu]:取钱之前的金额:%d\n", pthread_self(), balance);
balance -= 100;
pthread_mutex_unlock(&m);
pthread_exit(NULL);
}
// ./a.out 10
int main(int argc, char* argv[])
{
if(argc != 2)
{
printf("未输入线程数量\n");
return -1;
}
// 1、初始化互斥锁和条件变量
pthread_mutex_init(&m, NULL);
pthread_cond_init(&v, NULL);
// 2、创建线程
pthread_t tid;
int nThread_num = atoi(argv[1]);
for(int i = 0; i < nThread_num; i++)
{
//创建多个兄弟姐妹
pthread_create(&tid, NULL, routine, NULL);
}
// 3、让当前主线程给balance增值
int i = nThread_num
while(i--)
{
//对共享资源访问时需要加锁、解锁操作
pthread_mutex_lock(&m);
// 相当于家长汇钱
balance += 100;
// 向条件等待队列发送通知,汇钱后通知兄弟姐妹
pthread_cond_broadcast(&v);
pthread_mutex_unlock(&m);
sleep(2);//为了便于查看条件等待队列的过程
}
//退出主线程
pthread_exit(NULL);
//退出进程
//return 0;
}
可重入函数
一个函数如果同时被多个线程调用,返回的结果都是严格一致的,那么就是可重入函数,否则就是不可重入函数。
例如:排序函数是可重入函数,取地址函数是不可重入函数
多个线程调用同一可重入函数出现不同结果原因:
1、函数内部使用了共享资源,如全局变量
2、函数内部调用了其他不可重入函数
3、函数执行结果与硬件设备相关