Linux 多线程/进程同步
最近写作业学习了多线程/进程的经典同步问题,即生产者-消费者,在此做一些记录。主要是使用了semaphore.h
中的POSIX信号量。
多线程
原理
多线程模拟一对一生产者-消费者,核心是三个:生产线程、消费线程、缓冲区。生产线程和消费线程同时执行,不考虑相互的直接影响,而是仅通过缓冲区的满和空控制生产阻塞和消费阻塞。生产线程向缓冲区放置产品,并减小其剩余容量,当剩余容量为0时生产暂停/阻塞,消费线程从缓冲区提取产品,并增大其剩余容量,当库存为0时消费暂停/阻塞。
方案
多线程实现生产者-消费者模型,要实现几个方面:
- 产品缓冲区,为了比较好的模拟实际情况,我使用了产品结构体指针循环队列,生产者使用calloc生产一个商品,使用push将其放入队列尾部,消费者使用pop从队列首部获得产品结构体指针,显示其gid,并使用free将其消耗(同时防止内存泄漏)。
- 控制生产阻塞和消费阻塞,使用两个sem_t信号量实现,其中g_sem_full控制生产阻塞,初始值为缓冲区容量,生产者生产之前对其sem_wait,消费者消费之后对其sem_post,g_sem_empty控制消费阻塞,初始值为0,消费者消费之前对其sem_wait,生产者生产之后对其sem_post。
- 三是实现对队列操作的互斥,使用pthread互斥锁pthread_mutex_t实现,在队列操作之前请求上锁,在完成操作之后解锁。
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <semaphore.h>
#include <sys/syscall.h>
#include <sys/types.h>
#define QUEUE_SIZE 4
#define COUNT 20
struct goods {
int gid;
};
struct goods *queue[QUEUE_SIZE];
int head = 0;
int rear = 0;
int count = 0; // for using the full-size queue
int g_pcount = 0;
int g_ccount = 0;
pthread_mutex_t g_mutex;
sem_t g_sem_full;
sem_t g_sem_empty;
bool empty();
bool full();
int push(struct goods *);
struct goods *pop();
void *provider(void *);
void *consumer(void *);
int main()
{
srand(getpid());
sem_init(&g_sem_full, 0, QUEUE_SIZE);
sem_init(&g_sem_empty, 0, 0);
pthread_mutex_init(&g_mutex, NULL);
pthread_t p1;
pthread_t c1;
pthread_create(&p1, NULL, provider, NULL);
pthread_create(&c1, NULL, consumer, NULL);
pthread_join(p1, NULL);
pthread_join(c1, NULL);
pthread_mutex_destroy(&g_mutex);
sem_destroy(&g_sem_full);
sem_destroy(&g_sem_empty);
}
bool empty()
{
if (count == 0)
return true;
return false;
}
bool full()
{
if (count == QUEUE_SIZE)
return true;
return false;
}
int push(struct goods *item)
{
if (full())
return -1;
queue[rear] = item;
rear = (rear+1) % QUEUE_SIZE;
count++;
return rear;
}
struct goods *pop()
{
if (empty())
return NULL;
int temp = head;
head = (head+1)