Linux系统编程多线程之条件变量和信号量讲解
一.前言
生产者消费者模型引入
/*
简单的生产者消费者模型
如何查看错误:
ulimit -a
发现core file size (blocks, -c) 0
生成core文件
ulimit -c unlimited
gcc producust.c -o pro -lpthread -g编译后产生段错误
发现没有生成core文件
cat /proc/sys/kernel/core_pattern
如果输出的是一个路径(例如 /var/crash/core.%e.%p),核心文件可能会保存在指定的位置,而不是当前工作目录
设置核心文件始终生成在当前目录
sudo sysctl -w kernel.core_pattern=core
再次运行pro,即生成core文件
*/
/*
生产者消费者模型(粗略的版本)
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
struct Node{
int num;
struct Node *next;
};
//创建互斥量
pthread_mutex_t mutex;
// 头结点
struct Node * head = NULL;
void * producer(void * arg) {
// 不断的创建新的节点,添加到链表中
while(1) {
pthread_mutex_lock(&mutex);
struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand() % 1000;
printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
pthread_mutex_unlock(&mutex);
usleep(100);
}
return NULL;
}
void * customer(void * arg) {
while(1) {
pthread_mutex_lock(&mutex);
// 保存头结点的指针
struct Node * tmp = head;
if(head!=NULL)
{
head = head->next;
printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
free(tmp);
pthread_mutex_unlock(&mutex);
usleep(100);
}
else
{
pthread_mutex_unlock(&mutex);
}
}
return NULL;
}
int main() {
pthread_mutex_init(&mutex,NULL);
// 创建5个生产者线程,和5个消费者线程
pthread_t ptids[5], ctids[5];
for(int i = 0; i < 5; i++) {
pthread_create(&ptids[i], NULL, producer, NULL);
pthread_create(&ctids[i], NULL, customer, NULL);
}
for(int i = 0; i < 5; i++) {
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
while(1)
{
sleep(10);
}
pthread_mutex_destroy(&mutex);
pthread_exit(NULL);
return 0;
}
二.条件变量
条件变量不是锁,只是配合我们的互斥锁去使用
条件变量的类型:pthread_cond_t
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);销毁
int pthread_cond_destroy(pthread_cond_t*cond);一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);
案例示范
/*
初始化
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t*restrict attr);
销毁
int pthread_cond_destroy(pthread_cond_t*cond);
一直等待,并且需要通知解除
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t*restrict mutex);
等待多长的时间
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t*restrict mutex,const struct timespec *restrict abstime);
唤醒一个或多个等待
int pthread_cond_signal(pthread_cond_t*cond);
唤醒所有的
int pthread_cond_broadcast(pthread_cond_t*cond);
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
struct Node{
int num;
struct Node *next;
};
//创建互斥量
pthread_mutex_t mutex;
//创建条件变量
pthread_cond_t cond;
// 头结点
struct Node * head = NULL;
void * producer(void * arg) {
// 不断的创建新的节点,添加到链表中
while(1) {
pthread_mutex_lock(&mutex);
struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand() % 1000;
printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
//只要生产一个就通知消费者进行消费
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
usleep(100);
}
return NULL;
}
void * customer(void * arg) {
while(1) {
pthread_mutex_lock(&mutex);
// 保存头结点的指针
struct Node * tmp = head;
if(head!=NULL)
{
head = head->next;
printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
free(tmp);
pthread_mutex_unlock(&mutex);
usleep(100);
}
else
{
//没有数据,阻塞等待
//当wait这个函数调用阻塞时,会对这个互斥锁进行解锁,当不阻塞时会对这个互斥锁重新加锁
pthread_cond_wait(&cond,&mutex);
pthread_mutex_unlock(&mutex);
}
}
return NULL;
}
int main() {
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
// 创建5个生产者线程,和5个消费者线程
pthread_t ptids[5], ctids[5];
for(int i = 0; i < 5; i++) {
pthread_create(&ptids[i], NULL, producer, NULL);
pthread_create(&ctids[i], NULL, customer, NULL);
}
for(int i = 0; i < 5; i++) {
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
while(1)
{
sleep(10);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_exit(NULL);
return 0;
}
三.信号量
信号量:也是用于阻塞线程的
灯亮可以用,灯灭不可以用,不可以保证多线程数据安全问题,若需要保证,需要跟互斥锁一起使用
信号量的类型 sem_t
int sem_init(sem_t*sem,int pshared, unsigned int value);int sem_destroy(sem_t*sem);
int sem_wait(sem_t*sem);
int sem_trywait(sem_t*sem);
int sem_timedwait(sem_t*sem,const struct timespec *abs_timeout);
int sem_post(sem_t*sem);
int sem_getvalue(sem_t*sem,int*sval);
示范代码
/*
初始化
int sem_init(sem_t*sem,int pshared, unsigned int value);
-参数:
sem:信号量
pshared:代表用在线程(0)之间还是进程(其他值)之间
value:信号量中的值
释放资源
int sem_destroy(sem_t*sem);
等待
int sem_wait(sem_t*sem);
-没调用一次对信号量值-1,若剩下的值=0阻塞,>0直接返回,调用post+1
int sem_trywait(sem_t*sem);
等待多长时间
int sem_timedwait(sem_t*sem,const struct timespec *abs_timeout);
解锁信号量
int sem_post(sem_t*sem);
-没调用一次对信号量+1
int sem_getvalue(sem_t*sem,int*sval);
*/
#include <semaphore.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
struct Node{
int num;
struct Node *next;
};
//创建互斥量
pthread_mutex_t mutex;
//创建两个信号量
sem_t psem,csem;
// 头结点
struct Node * head = NULL;
void * producer(void * arg) {
// 不断的创建新的节点,添加到链表中
while(1) {
sem_wait(&psem);
pthread_mutex_lock(&mutex);
struct Node * newNode = (struct Node *)malloc(sizeof(struct Node));
newNode->next = head;
head = newNode;
newNode->num = rand() % 1000;
printf("add node, num : %d, tid : %ld\n", newNode->num, pthread_self());
pthread_mutex_unlock(&mutex);
sem_post(&csem);
usleep(100);
}
return NULL;
}
void * customer(void * arg) {
while(1) {
sem_wait(&csem);
pthread_mutex_lock(&mutex);
// 保存头结点的指针
struct Node * tmp = head;
head = head->next;
printf("del node, num : %d, tid : %ld\n", tmp->num, pthread_self());
free(tmp);
pthread_mutex_unlock(&mutex);
sem_post(&psem);
}
return NULL;
}
int main() {
sem_init(&psem,0,8);
sem_init(&csem,0,0);
pthread_mutex_init(&mutex,NULL);
// 创建5个生产者线程,和5个消费者线程
pthread_t ptids[5], ctids[5];
for(int i = 0; i < 5; i++) {
pthread_create(&ptids[i], NULL, producer, NULL);
pthread_create(&ctids[i], NULL, customer, NULL);
}
for(int i = 0; i < 5; i++) {
pthread_detach(ptids[i]);
pthread_detach(ctids[i]);
}
while(1)
{
sleep(10);
}
pthread_mutex_destroy(&mutex);
pthread_exit(NULL);
return 0;
}