数据混乱的原因:
建议锁!对公共数据进行保护。 所有线程应该在访问公共数据前先拿锁再访问。但是锁不具备强制性。
pthread_mutex lock 创建锁pthread_mutex_init 初始化pthread_mutex_lock 加锁pthread_mutex_unlock 解锁pthread_mutex_destory 销毁锁pthread_init函数调用成功)
EBUSY初始化互斥变量:
pthread_mutex_init() 动态初始化pthread_mutex_t cond = PTHREAD_MUTEX_INITIALIZER; 静态初始化作用: 互斥锁的初始化
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
参数:
mutex: 传出参数, 用于初始化的锁
attr: 互斥量属性, 默认为NULL
返回值:
成功: 0
失败: 错误值
restrict的作用:
作用: 销毁一个互斥锁
int pthread_mutex_destroy(pthread_mutex_t *mutex);
参数:
mutex: 待销毁的锁
返回值:
成功: 0
失败: 错误值
作用: 给指定的锁上锁, 若锁已经被上, 则阻塞线程
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
mutex: 待上锁的锁
返回值:
成功: 0
失败: 错误值
作用: 给指定的锁解锁, 同时唤醒阻塞在锁上的线程
int pthread_mutex_lock(pthread_mutex_t *mutex);
参数:
mutex: 待解锁的锁
返回值:
成功: 0
失败: 错误值
作用: 尝试给指定的锁加锁(不阻塞)
int pthread_mutex_trylock(pthread_mutex_t *mutex);
参数:
mutex: 待加锁的锁
返回值:
成功上锁: 0
该锁已经被上: 错误号(EBUSY)
lockint pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
用法和mutex函数类似
pthread_cond_init
pthread_cond_destroy
pthread_cond_wait // 等待某一个条件满足
pthread_cond_timedwait // 等待某一个条件满足, 并设置等待的时间
pthread_cond_signal // 一次通知至少一个阻塞在条件变量上的线程
pthread_cond_broadcast // 一次通知一堆阻塞在条件变量上的线程
初始化条件变量:
pthread_cond_init() 动态初始化pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 静态初始化int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
用法与互斥锁基本一直
作用:
1. 阻塞等待条件变量cond满足
2. 释放已经掌握的互斥锁(pthread_mutex_unlock)
===========1,2两步为一个原子操作============
3. 当被唤醒的时候, pthread_cond_wait函数返回时, 解除阻塞并重新申请获取互斥锁(pthread_mutex_lock)
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
生产者,消费者模型
公共步骤:
pthread_mutex_t mutexpthread_mutex_init()pthread_mutex_lock| 消费者 | 生产者 |
|---|---|
1. 等待条件满足pthread_cond_wait() | 1. 生产数据 |
| 2. 访问共享数据 | 2. 加锁 pthread_mutex_lock() |
| 3.循环 | 3. 将数据放到公共区域 |
4. 解锁pthread_mutex_unlock() | |
| 5.通知阻塞在条件上的线程 | |
| 6.循环 |
生产者,消费者模型代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
void err_thread(int ret, const char *str)
{
if (ret != 0)
{
fprintf(stderr, "%s:%s\n", str, strerror(ret));
pthread_exit(NULL);
}
}
struct msg
{
int num;
struct msg *next;
};
struct msg *head;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 定义,初始化一个互斥量
pthread_cond_t has_data = PTHREAD_COND_INITIALIZER; // 定义,初始化一个条件变量
void *producer(void *arg)
{
while (1)
{
struct msg *mp = (struct msg *)malloc(sizeof(struct msg));
mp->num = rand() % 1000 + 1; // 模拟生产了一个数据
printf("--produce %d\n", mp->num);
pthread_mutex_lock(&mutex); // 加锁 互斥量
mp->next = head; // 写公区域的操作
head = mp;
pthread_mutex_unlock(&mutex); // 解锁 互斥量
pthread_cond_signal(&has_data); // 唤醒阻塞在has_data上的线程
sleep(rand() % 3);
}
return NULL;
}
void *consumer(void *arg)
{
while (1)
{
struct msg *mp;
pthread_mutex_lock(&mutex); // 加锁 互斥量
while (head == NULL) // 当有多个消费者的时候,要用while,防止被唤醒以后线程没有资源
{
pthread_cond_wait(&has_data, &mutex); // 阻塞等待条件变量, 解锁
} // 返回时会重新加锁mutex
mp = head;
head = mp->next;
pthread_mutex_unlock(&mutex); // 解锁 互斥量
printf("--------consumer id: %lu :%d\n", pthread_self(), mp->num);
free(mp);
sleep(rand() % 3);
}
return NULL;
}
int main()
{
int ret;
pthread_t pid, cid;
srand(time(NULL));
ret = pthread_create(&pid, NULL, producer, NULL);
if (ret != 0)
err_thread(ret, "pthread_create produser error");
ret = pthread_create(&cid, NULL, consumer, NULL);
if (ret != 0)
err_thread(ret, "pthread_create consumer error");
ret = pthread_create(&cid, NULL, consumer, NULL);
if (ret != 0)
err_thread(ret, "pthread_create consumer error");
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}
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 *restrict sem, const struct timespec *restrict abs_timeout);
int sem_post(sem_t *sem);
sem_wait:信号量大于0, 则信号量-- (pthread_mutex_lock)
信号量等于0, 造成线程阻塞
sem_post:信号量++, 同时唤醒阻塞在信号量上的线程 (pthread_mytex_unlock)
信号量为N时, 再次++就会阻塞
信号量的初值,决定了占用信号量的线程的个数
作用:初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
sem: 信号量
pshared:
0: 线程间同步
1: 进程间同步
value: N值, 指定同时访问的线程数
返回值:
成功: 0
失败: -1, 设置errno
int sem_timedwait(sem_t *restrict sem, const struct timespec *restrict abs_timeout);
参数:
sem: 等待的信号量,从1970.1.1开始到现在的时间
abs_timeout: 绝对时间
struct timespec {
time_t tv_sec; /* Seconds */
long tv_nsec; /* Nanoseconds [0 .. 999999999] */
};
定时1s:
time_t cur = time(NULL); // 获取当前的时间
struct timespec t; // 定义timespec结构体变量t
t.tv_sec = cur + 1; // 定时1s
t.tv_nsec = t.tv_sec + 100;
sem_timedwaoit(&sem, &t); // 传参
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <semaphore.h>
#define NUM 5
int queue[NUM]; // 全局数组实现环形队列
sem_t blank_number, product_number; // 空格子信号量, 产品信号量
void *producer(void *arg) {
int i = 0;
while (1) {
sem_wait(&blank_number); // 生产者将格子数--
queue[i] = rand() % 1000 + 1; // 生产一个产品
printf("----Produce---%d\n", queue[i]);
sem_post(&product_number); // 产品数++
i = (i + 1) % NUM;
sleep(rand() % 1);
}
}
void *consumer(void * arg) {
int i = 0;
while (1) {
sem_wait(&product_number); // 产品数--
printf("-Consume---%d\n", queue[i]);
queue[i] = 0;
sem_post(&blank_number); // 格子数++
i = (i + 1) % NUM;
sleep(rand() % 3);
}
}
int main() {
pthread_t pid, cid;
sem_init(&blank_number, 0, NUM);
sem_init(&product_number, 0, 0);
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
sem_destroy(&blank_number);
sem_destroy(&product_number);
return 0;
}