一、 生产者消费者问题
生产者消费者共享缓冲区,生产者向缓冲区中放数据,消费者从缓冲取中取数据,当缓冲区中被放满时,生产者进程就必须进入挂起状态,直到消费者从缓冲中取走数据时,生产者才能继续向缓冲区中存放数据,同样当缓冲取中没有数据时,消费者进程就必须进入挂起休眠状态,直到生产者向缓冲区中放入数据时,消费者才能被唤醒继续从缓冲区中取走数据。
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式。
————————————————
采用互斥锁实现,线程间同步
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#define bufsize 10 //设置缓存区大小
typedef struct node
{
int val;
struct node *next;
} node;
int count = 0;
node *head = NULL;
pthread_mutex_t point = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t full = PTHREAD_COND_INITIALIZER;
pthread_cond_t empty = PTHREAD_COND_INITIALIZER;
void *producer()
{
node *t;
while (1)
{
pthread_mutex_lock(&point);
while (count >= bufsize)
pthread_cond_wait(&full, &point);
t = (node *)malloc(sizeof(node));
t->val = rand() % 100 + 1;
count++;
t->next = head;
head = t;
printf("--producer %d count %d \n", t->val, count);
pthread_mutex_unlock(&point);
pthread_cond_signal(&empty);
sleep(rand() % 2);
}
}
void *consumer()
{
node *t;
while (1)
{
pthread_mutex_lock(&point);
while (count == 0)
pthread_cond_wait(&empty, &point);
t = head;
head = head->next;
printf("--consumer %d count %d\n", t->val, count);
free(t);
count--;
pthread_mutex_unlock(&point);
pthread_cond_signal(&full);
sleep(rand() % 5);
}
}
int main()
{
pthread_t cid, pid;
srand(time(NULL));
if (pthread_create(&pid, NULL, producer, NULL) != 0)
{
perror("pthread_creat cid error:");
exit(1);
}
if (pthread_create(&cid, NULL, consumer, NULL) != 0)
{
perror("pthread_creat pid error:");
exit(1);
}
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}
二、 哲学家问题
有五个哲学家绕着圆桌坐,每个哲学家面前有一盘面,两人之间有一支筷子,这样每个哲学家左右各有一支筷子。哲学家有2个状态,思考或者拿起筷子吃饭。如果哲学家拿到一只筷子,不能吃饭,直到拿到2只才能吃饭,并且一次只能拿起身边的一支筷子。一旦拿起便不会放下筷子直到把饭吃完,此时才把这双筷子放回原处。如果,很不幸地,每个哲学家拿起他或她左边的筷子,那么就没有人可以吃到饭了。
思路:采用信号量保持线程同步/互斥,临界区访问问题以及避免死锁。
方法1:同时让4个哲学家进行竞争5个筷子,避免死锁
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
#define n 5 //五个哲学家
sem_t a[n]; //n个信号量代表筷子
sem_t t;
void *ptr1(void *arg) //方法1:同时让4个哲学家进行竞争5个筷子,避免死锁
{
int i = (*(int *)arg);
while (1)
{
printf("哲学家%d思考\n", i);
sem_wait(&t);
printf("哲学家%d饿了\n", i);
sem_wait(&a[i]);
printf("哲学家%d拿起了%d筷子,一根不能吃\n", i, i);
sem_wait(&a[(i + 1) % n]);
printf("哲学家%d拿起了%d %d筷子,开始吃饭\n", i, i, (i + 1) % n);
sleep(3);
sem_post(&a[i]);
sem_post(&(a[(i + 1) % n]));
sem_post(&t);
}
}
int main()
{
pthread_t b[5];
sem_init(&t, 0, 4); //设置信号量为4,即同时只有4位发生竞争
for (int i = 0; i < 5; i++)
{
sem_init(&a[i], 0, 1);
pthread_create(&b[i], NULL, ptr1, &i);
}
for (int i = 0; i < n; i++)
{
pthread_join(b[i], NULL);
}
for (int i = 0; i < n; i++)
{
sem_destroy(&a[i]);
}
return 0;
}
方法2:同时让4个哲学家进行竞争5个筷子,避免死锁
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
#define n 5 //五个哲学家
sem_t a[n]; //n个信号量代表筷子
sem_t t;
void *ptr2(*arg) //方法2:对于一个哲学家要就餐,如果能同时拿到2根筷子就餐,
{
//如果不行,就释放所有筷子
int i = (*(int *)arg);
while (1)
{
if(sem_trywait(&a[i])==-1)
continue;
printf("哲学家%d拿起了%d筷子,一根不能吃\n", i, i);
sleep(rand()%3);
if (sem_trywait(&a[(i+1)%n])==-1)
{
sem_post(&a[i]);
continue;
}
printf("哲学家%d拿起了%d %d筷子,开始吃饭\n", i, i, (i + 1) % n);
sleep(rand()%3);
sem_post(&a[i]);
sem_post(&(a[(i + 1) % n]));
}
}
int main()
{
pthread_t b[5];
srand(time(NULL));
sem_init(&t, 0, 4); //设置信号量为4,即同时只有4位发生竞争
for (int i = 0; i < 5; i++)
{
sem_init(&a[i], 0, 1);
pthread_create(&b[i], NULL, ptr2, &i);
}
for (int i = 0; i < n; i++)
{
pthread_join(b[i], NULL);
}
for (int i = 0; i < n; i++)
{
sem_destroy(&a[i]);
}
return 0;
}
/
方法3:对于奇数先左后右,偶数相反
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <errno.h>
#include <semaphore.h>
#define n 5 //五个哲学家
sem_t a[n]; //n个信号量代表筷子
sem_t t;
pthread_mutex_t ltck;
void *ptr2(*arg) //方法3:对于奇数先左后右,偶数相反
{
int i = (*(int *)arg);
while (1)
{
printf("哲学家%d思考\n", i);
printf("哲学家%d饿了\n", i);
if (i % 2 == 0)
{
sem_wait(&a[i]);
printf("哲学家%d拿起了%d筷子,一根不能吃\n", i, i);
sem_wait(&a[(i + 1) % n]);
printf("哲学家%d拿起了%d %d筷子,开始吃饭\n", i, i, (i + 1) % n);
}
else
{
sem_wait(&a[(i + 1) % n]);
printf("哲学家%d拿起了%d筷子,一根不能吃\n", i, (i + 1) % n);
sem_wait(&a[i]);
printf("哲学家%d拿起了%d %d筷子,开始吃饭\n", i, (i + 1) % n, i);
}
sleep(rand()%3);
sem_post(&a[i]);
sem_post(&a[(i + 1) % n]);
}
}
int main()
{
pthread_t b[5];
pthread_mutex_init(<ck,NULL);
srand(time(NULL));
sem_init(&t, 0, 4); //设置信号量为4,即同时只有4位发生竞争
for (int i = 0; i < 5; i++)
{
sem_init(&a[i], 0, 1);
pthread_create(&b[i], NULL, ptr2, &i);
}
for (int i = 0; i < n; i++)
{
pthread_join(b[i], NULL);
}
for (int i = 0; i < n; i++)
{
sem_destroy(&a[i]);
}
return 0;
}