(3)编写一个程序primer_pro3.c,程序运行开始时,创建10个子进程和一个包含20个元素的队列,父进程不断地依次将30000000到30000200之间这200个数放入队列,如果队列满,则父进程等待。 队列的定义可参考如下: #define MAXSIZE 20 struct quequ_st{ int finished; int head; int tail; char data[MAXSIZE]; int count; }; 队列成员finished初始
时间: 2024-04-07 13:30:47 浏览: 59
值为0,当父进程将所有数据放入队列后将其设为1。head和tail分别表示队列的头和尾在data数组中的下标,count表示队列中元素的个数。子进程从队列中取出数据并计算质数,如果队列为空,则子进程等待。当父进程将所有数据放入队列后,等待所有子进程结束,并打印出所有子进程计算的质数的和。程序中应该使用进程同步机制。
相关问题
(3) 实现进程池计算素数:编写一个程序primer_pro3.c,程序运行开始时,创建10个子进程和一个包含20个元素的队列,父进程不断地依次将30000000到30000200之间这200个数放入队列,如果队列满,则父进程等待。 队列的定义可参考如下: #define MAXSIZE 20 struct quequ_st{ int finished; //父进程是否已将所有200个整数放入了队列 int head; //队列头 int tail; //队列尾 char data[MAXSIZE]; //队列数据 int count; //当前队列中数据个数 }; 队列成员finished初始值为0,当父进程将全部200个整数全部放入队列后,将finished置为1,并等待10个子进程结束。 子进程依次不断地从队列中取出一个整数,并判断这个整数是不是素数,如果是素数,则输出这个进程的进程号以及这个整数。当然,每次从队列中取数之前,首先需要判断finished是否为1并且队列是否为空,如果是,则子进程结束。
下面是实现进程池计算素数的程序primer_pro3.c:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <pthread.h>
#include <string.h>
#include <math.h>
#define MAXSIZE 20
struct queue_st {
int finished; //父进程是否已将所有200个整数放入了队列
int head; //队列头
int tail; //队列尾
int data[MAXSIZE]; //队列数据
int count; //当前队列中数据个数
};
struct queue_st queue = {0, 0, 0, {0}, 0};
void* prime(void* arg);
int main() {
pid_t pid;
int i, num;
pthread_t tid;
//创建子进程
for (i = 0; i < 10; i++) {
pid = fork();
if (pid < 0) {
perror("fork error");
exit(1);
} else if (pid == 0) {
//子进程
pthread_create(&tid, NULL, prime, NULL);
pthread_join(tid, NULL);
exit(0);
}
}
//父进程
for (num = 30000000; num < 30000200; num++) {
while (queue.count == MAXSIZE) {
//队列满,等待
usleep(100000);
}
queue.data[queue.tail] = num;
queue.tail = (queue.tail + 1) % MAXSIZE;
queue.count++;
if (queue.count == MAXSIZE) {
//队列满,通知子进程
kill(0, SIGUSR1);
}
}
queue.finished = 1;
//等待子进程结束
for (i = 0; i < 10; i++) {
wait(NULL);
}
return 0;
}
void* prime(void* arg) {
int num, i, is_prime;
while (1) {
//判断队列是否为空
while (queue.count == 0) {
if (queue.finished) {
//父进程已将所有数放入队列,退出
pthread_exit(NULL);
}
//等待父进程放入数
pause();
}
num = queue.data[queue.head];
queue.head = (queue.head + 1) % MAXSIZE;
queue.count--;
is_prime = 1;
for (i = 2; i <= sqrt(num); i++) {
if (num % i == 0) {
is_prime = 0;
break;
}
}
if (is_prime) {
printf("pid=%d, num=%d\n", getpid(), num);
}
}
}
```
程序首先创建10个子进程,并且每个子进程都调用prime函数来处理队列中的数据。当父进程将一个数放入队列时,如果队列已满,则父进程等待。如果队列满了,父进程会发送一个SIGUSR1信号给所有子进程,以通知它们队列已经满了。每个子进程都通过调用pause函数来等待父进程的通知。当一个子进程从队列中取出一个数后,它会判断这个数是否为素数,如果是,则输出进程号以及这个整数。如果队列为空,子进程会等待父进程放入数据。如果父进程已经将所有数据放入队列,那么子进程就退出。最后,父进程等待所有子进程结束后,程序才结束。
编写一个程序primer_pro3.c,用进程池实现。程序运行开始时,创建10个子进程和一个包含20个元素的队列,父进程不断地依次将30000000到30000200之间这200个数放入队列,如果队列满,则父进程等待。
好的,这是一个比较典型的进程池实现的例子。下面是代码:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <string.h>
#define MAX_PROCESSES 10
#define QUEUE_SIZE 20
typedef struct {
long mtype;
int data;
} msg_t;
int msqid;
void worker() {
msg_t msg;
while (1) {
if (msgrcv(msqid, &msg, sizeof(msg_t), 1, 0) == -1) {
perror("msgrcv");
exit(1);
}
int num = msg.data;
printf("Processed: %d\n", num*num);
}
}
void parent() {
int i;
for (i = 30000000; i < 30000200; i++) {
msg_t msg;
msg.mtype = 1;
msg.data = i;
if (msgsnd(msqid, &msg, sizeof(msg_t), IPC_NOWAIT) == -1) {
perror("msgsnd");
exit(1);
}
printf("Sent: %d\n", i);
}
}
int main() {
int i;
pid_t pid;
key_t key = ftok(".", 'q');
msqid = msgget(key, IPC_CREAT | 0666);
for (i = 0; i < MAX_PROCESSES; i++) {
pid = fork();
if (pid == -1) {
perror("fork");
exit(1);
} else if (pid == 0) {
worker();
exit(0);
}
}
parent();
for (i = 0; i < MAX_PROCESSES; i++) {
wait(NULL);
}
msgctl(msqid, IPC_RMID, NULL);
return 0;
}
```
程序中使用了一个消息队列来实现子进程和父进程之间的通信,父进程向队列中发送数据,子进程从队列中取出数据进行处理。
消息队列的创建和删除使用了`msgget`和`msgctl`函数,消息的发送和接收使用了`msgsnd`和`msgrcv`函数。
程序中创建了10个子进程,每个子进程通过循环调用`worker`函数来不断从队列中取出数据进行处理。
父进程则通过循环调用`parent`函数来不断向队列中发送数据,如果队列已满,则等待。
注意,程序中使用了`IPC_NOWAIT`标志来避免`msgsnd`函数的阻塞,这样可以让父进程在队列已满的情况下不会一直等待,而是立即返回并继续发送下一个数据。
阅读全文