Linux多线程编程学习代码记录(代码已上传gitee,点个Star也不错哦!)
https://gitee.com/chenshao777/linux_thread.git
【Linux多线程编程-自学记录】
01.线程ID与进程ID
02.创建线程
03.主线程与子线程生命周期
04.线程链接-pthread_join
05.取消线程
06.向线程发送信号-sigaction
07.线程清除
08.Linux多线程互斥量
09.Linux多线程之读写锁
10.条件变量
10.条件变量
笔记:
1.条件变量引入
需要一种机制,当互斥量被锁柱后,发现当前线程还是无法完成自己的操作
那么它应该自己释放互斥量,让其他线程得以工作
方法1:采用轮询方式
方法2:让系统查询条件,使用系统条件变量 pthread_cond_t cond
2.条件变量初始化和销毁
条件变量使用之前需要初始化
1、pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
2、int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr)
第一个参数是条件变量
第二个参数默认属性为空NULL
条件变量使用完成之后需要销毁
int pthread_cond_destroy(pthread_cond_t *cond);
3.条件变量的使用
条件变量使用雷要配合互斥量
int pthread_cond_wait(pthread_cond_t *restrict cond.
pthread_mutex_t *restrict mutex);
1、使用pthread_cond_wait等待条件变为真。传递给pthread_cond_wait的互斥量对条件进行保护,调用者把锁住的互斥量传递给函数。
2、这个函数将线程放到等待条件的线程列表上,然后对互斥量进行解锁,这是个原子操作。当条件满足时这个函数返回,返回以后维续对互斥量加锁。
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
3、这个函数与pthread_cond_wait类似,只是多一个timeout,如果到了指定的时间条件还不满足,那么就返回。
时间用下面的结构体表示
struct timespec{
time_t tv_sec;
long tv_nsec;
}:
注意。这个时间是绝对时间。例如你要等待3分钟,就要把当前时间加上3分钟然后转换到timespec·而不是直接将3分钟转换到timespec
当条件满足的时候,需要唤醒等侍条件的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
Iint pthread_cond_signal(pthread_cond_t *cond);
1、pthread_cond_broadcast 唤醒等待条件的所有线程(广播)
2、pthread_cond_signal 至少唤醒等待条件的某一个线程
注意,一定要在条件改变以后在唤醒线程
spu.h文件
#ifndef _SPU_H_
#define _SPU_H_
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<sys/types.h>
#include<signal.h>
#include<errno.h>
#endif
10.thread_cond.c文件
1.创建两个线程,都对 money 全局变量进行操作
2.线程1每次对 money 加10
3.线程2每次对 money 加0.01
4.如果出现互斥的情况,线程1会输出小数
/*
1.创建一个生产者,两个消费者
2.生产者0.5秒生产一个产品,并且发送条件变量广播唤醒等待的线程
3.消费者1秒消费一个产品
4.条件变量要配合互斥锁
*/
#include "spu.h"
#include <time.h>
/*产品结构体*/
typedef struct product{
int num;
struct product *next; //指向下一个产品
}product_t;
/*定义第一个产品:链表首节点*/
product_t *head = NULL;
/*初始化互斥锁*/
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //使用宏定义初始化互斥锁
/*初始化条件变量*/
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //使用宏定义初始化条件变量
/*
生产者线程
*/
void *thread_product(void *arg)
{
for(;;)
{
//申请一个新的节点
product_t *p = (product_t*)malloc(sizeof(product_t));
p->num = rand() % 100 + 1; //生成 1-100 之间的随机数
//加锁
pthread_mutex_lock(&mutex);
//向链表表头加节点
p->next = head;
head = p;
printf("生产者:%d\n",head->num);
//解锁
pthread_mutex_unlock(&mutex);
//通知所有/单个消费者
pthread_cond_broadcast(&cond);
usleep(500000);
}
}
/*
消费者线程1
*/
void *thread_consume01(void *arg)
{
for(;;)
{
//加锁
pthread_mutex_lock(&mutex);
//如果没有产品则等待
if(head->next == NULL)
//等待被通知,如果无通知,则自解锁(通过第二个参数),进入阻塞状态,等待被系统唤醒
pthread_cond_wait(&cond, &mutex);
//得到通知,开始消费
printf("消费者1:%d\n", head->num);
head = head->next;
//解锁
pthread_mutex_unlock(&mutex);
usleep(1000000);
}
}
/*
消费者线程2
*/
void *thread_consume02(void *arg)
{
for(;;)
{
//加锁
pthread_mutex_lock(&mutex);
//如果没有产品则等待
if(head->next == NULL)
//等待被通知,如果无通知,则自解锁(通过第二个参数),进入阻塞状态,等待被系统唤醒
pthread_cond_wait(&cond, &mutex);
//得到通知,开始消费
printf("消费者2:%d\n", head->num);
head = head->next;
//解锁
pthread_mutex_unlock(&mutex);
usleep(1000000);
}
}
int main()
{
srand((unsigned int)time(NULL)); //设置随机种子
pthread_t pro_pid, con_pid1, con_pid2;
void *_return1,*_return2,*_return3;
/*创建生产者线程*/
pthread_create(&pro_pid, NULL, thread_product, NULL);
/*创建消费者线程1*/
pthread_create(&con_pid1, NULL, thread_consume01, NULL);
/*创建消费者线程2*/
pthread_create(&con_pid2, NULL, thread_consume02, NULL);
/*等待线程结束*/
pthread_join(pro_pid,_return1);
pthread_join(con_pid1,_return2);
pthread_join(con_pid2,_return3);
/*销毁互斥量*/
pthread_mutex_destroy(&mutex);
/*销毁条件变量*/
pthread_cond_destroy(&cond);
}