先决条件 – 同步,临界区
问题:生产者消费者问题(或有界缓冲区问题)描述了两个进程,生产者和消费者,它们共享一个公共的、固定大小的缓冲区,用作队列。生产者生产一个项目并将其放入缓冲区。如果缓冲区已满,那么生产者将不得不等待缓冲区中的空块。消费者从缓冲区消费一个项目。如果缓冲区已经为空,那么消费者将不得不等待缓冲区中的项目。使用共享内存为两个进程实现彼得森算法,以便它们之间存在互斥。解决方案应该没有同步问题。
彼得森算法——
// code for producer (j)
// producer j is ready
// to produce an item
flag[j] = true;
// but consumer (i) can consume an item
turn = i;
// if consumer is ready to consume an item
// and if its consumer's turn
while (flag[i] == true && turn == i)
{ // then producer will wait }
// otherwise producer will produce
// an item and put it into buffer (critical Section)
// Now, producer is out of critical section
flag[j] = false;
// end of code for producer
//--------------------------------------------------------
// code for consumer i
// consumer i is ready
// to consume an item
flag[i] = true;
// but producer (j) can produce an item
turn = j;
// if producer is ready to produce an item
// and if its producer's turn
while (flag[j] == true && turn == j)
{ // then consumer will wait }
// otherwise consumer will consume
// an item from buffer (critical Section)
// Now, consumer is out of critical section
flag[i] = false;
// end of code for consumer
彼得森算法的解释——
彼得森算法用于同步两个进程。它使用两个变量,大小2的布尔标志阵列和一个int变量转来完成它。
在解决方案中,i 代表消费者,j 代表生产者。最初这些标志是假的。当一个进程想要执行它的临界区时,它将它的标志设置为 true 并作为另一个进程的索引。这意味着该进程想要执行,但它会允许其他进程先运行。该进程执行忙等待,直到另一个进程完成它自己的临界区。
在此之后,当前进程进入它的临界区并从共享缓冲区中添加或删除一个随机数。完成临界区后,它将自己的标志设置为 false,表明它不再希望执行。
程序在退出前运行一段固定的时间。这个时间可以通过改变宏 RT 的值来改变。
// C program to implement Peterson’s Algorithm
// for producer-consumer problem.
#include
#include
#include
#include
#include
#include
#include
#include
#define _BSD_SOURCE
#include
#include
#define BSIZE 8 // Buffer size
#define PWT 2 // Producer wait time limit
#define CWT 10 // Consumer wait time limit
#define RT 10 // Program run-time in seconds
int shmid1, shmid2, shmid3, shmid4;
key_t k1 = 5491, k2 = 5812, k3 = 4327, k4 = 3213;
bool* SHM1;
int* SHM2;
int* SHM3;
int myrand(int n) // Returns a random number between 1 and n
{
time_t t;
srand((unsigned)time(&t));
return (rand() % n + 1);
}
int main()
{
shmid1 = shmget(k1, sizeof(bool) * 2, IPC_CREAT | 0660); // flag
shmid2 = shmget(k2, sizeof(int) * 1, IPC_CREAT | 0660); // turn
shmid3 = shmget(k3, sizeof(int) * BSIZE, IPC_CREAT | 0660); // buffer
shmid4 = shmget(k4, sizeof(int) * 1, IPC_CREAT | 0660); // time stamp
if (shmid1 < 0 || shmid2 < 0 || shmid3 < 0 || shmid4 < 0) {
perror("Main shmget error: ");
exit(1);
}
SHM3 = (int*)shmat(shmid3, NULL, 0);
int ix = 0;
while (ix < BSIZE) // Initializing buffer
SHM3[ix++] = 0;
struct timeval t;
time_t t1, t2;
gettimeofday(&t, NULL);
t1 = t.tv_sec;
int* state = (int*)shmat(shmid4, NULL, 0);
*state = 1;
int wait_time;
int i = 0; // Consumer
int j = 1; // Producer
if (fork() == 0) // Producer code
{
SHM1 = (bool*)shmat(shmid1, NULL, 0);
SHM2 = (int*)shmat(shmid2, NULL, 0);
SHM3 = (int*)shmat(shmid3, NULL, 0);
if (SHM1 == (bool*)-1 || SHM2 == (int*)-1 || SHM3 == (int*)-1) {
perror("Producer shmat error: ");
exit(1);
}
bool* flag = SHM1;
int* turn = SHM2;
int* buf = SHM3;
int index = 0;
while (*state == 1) {
flag[j] = true;
printf("Producer is ready now.\n\n");
*turn = i;
while (flag[i] == true && *turn == i)
;
// Critical Section Begin
index = 0;
while (index < BSIZE) {
if (buf[index] == 0) {
int tempo = myrand(BSIZE * 3);
printf("Job %d has been produced\n", tempo);
buf[index] = tempo;
break;
}
index++;
}
if (index == BSIZE)
printf("Buffer is full, nothing can be produced!!!\n");
printf("Buffer: ");
index = 0;
while (index < BSIZE)
printf("%d ", buf[index++]);
printf("\n");
// Critical Section End
flag[j] = false;
if (*state == 0)
break;
wait_time = myrand(PWT);
printf("Producer will wait for %d seconds\n\n", wait_time);
sleep(wait_time);
}
exit(0);
}
if (fork() == 0) // Consumer code
{
SHM1 = (bool*)shmat(shmid1, NULL, 0);
SHM2 = (int*)shmat(shmid2, NULL, 0);
SHM3 = (int*)shmat(shmid3, NULL, 0);
if (SHM1 == (bool*)-1 || SHM2 == (int*)-1 || SHM3 == (int*)-1) {
perror("Consumer shmat error:");
exit(1);
}
bool* flag = SHM1;
int* turn = SHM2;
int* buf = SHM3;
int index = 0;
flag[i] = false;
sleep(5);
while (*state == 1) {
flag[i] = true;
printf("Consumer is ready now.\n\n");
*turn = j;
while (flag[j] == true && *turn == j)
;
// Critical Section Begin
if (buf[0] != 0) {
printf("Job %d has been consumed\n", buf[0]);
buf[0] = 0;
index = 1;
while (index < BSIZE) // Shifting remaining jobs forward
{
buf[index - 1] = buf[index];
index++;
}
buf[index - 1] = 0;
} else
printf("Buffer is empty, nothing can be consumed!!!\n");
printf("Buffer: ");
index = 0;
while (index < BSIZE)
printf("%d ", buf[index++]);
printf("\n");
// Critical Section End
flag[i] = false;
if (*state == 0)
break;
wait_time = myrand(CWT);
printf("Consumer will sleep for %d seconds\n\n", wait_time);
sleep(wait_time);
}
exit(0);
}
// Parent process will now for RT seconds before causing child to terminate
while (1) {
gettimeofday(&t, NULL);
t2 = t.tv_sec;
if (t2 - t1 > RT) // Program will exit after RT seconds
{
*state = 0;
break;
}
}
// Waiting for both processes to exit
wait();
wait();
printf("The clock ran out.\n");
return 0;
}
输出:
Producer is ready now.
Job 9 has been produced
Buffer: 9 0 0 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 8 has been produced
Buffer: 9 8 0 0 0 0 0 0
Producer will wait for 2 seconds
Producer is ready now.
Job 13 has been produced
Buffer: 9 8 13 0 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 23 has been produced
Buffer: 9 8 13 23 0 0 0 0
Producer will wait for 1 seconds
Consumer is ready now.
Job 9 has been consumed
Buffer: 8 13 23 0 0 0 0 0
Consumer will sleep for 9 seconds
Producer is ready now.
Job 15 has been produced
Buffer: 8 13 23 15 0 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 13 has been produced
Buffer: 8 13 23 15 13 0 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 11 has been produced
Buffer: 8 13 23 15 13 11 0 0
Producer will wait for 1 seconds
Producer is ready now.
Job 22 has been produced
Buffer: 8 13 23 15 13 11 22 0
Producer will wait for 2 seconds
Producer is ready now.
Job 23 has been produced
Buffer: 8 13 23 15 13 11 22 23
Producer will wait for 1 seconds
The clock ran out.