我正在撰寫一個帶有管道的父行程通信程式,關鍵是我需要從端線發送不同數量的資料(大資料),但我不知道如何將訊息“拆分”成更小的資料(4096每個位元組)并將它們按順序發送到讀取端。我嘗試了一個回圈,使(訊息大小/4096)迭代,但它沒有作業,所以我放棄了這個想法。
這是我的代碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#define SIZES 6
#define KB 1024
//1KB, 10KB, 100KB, 1MB, 10MB, 100MB
int PACK_SIZES[SIZES] = {1*KB, 10*KB, 100*KB, 1*KB*KB, 10*KB*KB, 100*KB*KB};
//int PACK_TESTS[SIZES] = {1000,1000,100,100,10,5};
int PACK_TESTS[SIZES] = {6,5,4,3,2,1};
void fill(char * bufptr, size_t size);
int main() {
int tests_amount;
size_t size;
//pipefd[0] -> lectura
//pipefd[1] -> escritura
int pipefd[2];
int r; //Variable de retorno.
pid_t pid;
r = pipe(pipefd);
if (r < 0){
perror("Error al crear la tubería");
exit(-1);
}
printf("Medidas de envío de paquetes con comunicación mediante Tuberías.\n\n");
pid = fork();
if (pid == (pid_t) -1){
perror("Error en fork");
exit(-1);
}
for (int i = 0; i < SIZES; i ){
int packages_amount;
tests_amount = PACK_TESTS[i];
size = PACK_SIZES[i];
float time0, time1;
float total_time = 0;
char *write_buffer[size];
char *read_buffer[size];
fill(write_buffer, size);
for (int j = 1; j <= tests_amount; j ){
time0 = clock();
if (pid == 0){
//Consumidor
close(pipefd[1]);
read(pipefd[0], read_buffer, size);
close(pipefd[0]);
//printf("\n Mensaje recibido de tama?o %d: %d \n", size, strlen(read_buffer));
}else {
//Productor
close(pipefd[0]);
write(pipefd[1], write_buffer, size);
close(pipefd[1]);
}
time1 = clock();
double tiempo = (double)(time1) / CLOCKS_PER_SEC-(double)(time0) / CLOCKS_PER_SEC;
total_time = total_time tiempo;
}
printf("El promedio con %d Bytes y %d pruebas es: %f seg. \n\n",size,tests_amount,total_time/tests_amount);
total_time = 0;
}
return 0;
}
void fill(char * bufptr, size_t size){
static char ch = 'A';
int filled_count;
//printf("size is %d\n", size);
if (size != 0){
memset(bufptr, ch, size);
} else {
memset(bufptr, 'q', size);
}
bufptr[size-1] = '\0';
if (ch > 90)
ch = 65;
filled_count = strlen(bufptr);
//printf("Bytes escritos: %d\n\n", filled_count);
//printf("buffer filled is:%s\n", bufptr);
ch ;
}
我收到類似以下錯誤的資訊(我知道這是種族限制的,但我不知道如何解決它:c):
Medidas de envío de paquetes con comunicación mediante Tuberías.
El promedio con 1024 Bytes y 6 pruebas es: 0.000002 seg.
Mensaje recibido de tama?o 1024: 1023
Mensaje recibido de tama?o 1024: 1023
Mensaje recibido de tama?o 1024: 1023
Mensaje recibido de tama?o 1024: 1023
Mensaje recibido de tama?o 1024: 1023
Mensaje recibido de tama?o 1024: 1023
El promedio con 10240 Bytes y 5 pruebas es: 0.000001 seg.
El promedio con 1024 Bytes y 6 pruebas es: 0.000012 seg.
Mensaje recibido de tama?o 10240: 0
Mensaje recibido de tama?o 10240: 0
Mensaje recibido de tama?o 10240: 0
Mensaje recibido de tama?o 10240: 0
Mensaje recibido de tama?o 10240: 0
El promedio con 10240 Bytes y 5 pruebas es: 0.000005 seg.
El promedio con 102400 Bytes y 4 pruebas es: 0.000001 seg.
Mensaje recibido de tama?o 102400: 0
Mensaje recibido de tama?o 102400: 0
Mensaje recibido de tama?o 102400: 0
Mensaje recibido de tama?o 102400: 0
El promedio con 102400 Bytes y 4 pruebas es: 0.000008 seg.
Segmentation fault (core dumped)
uj5u.com熱心網友回復:
有兩個三個問題
char *write_buffer[size];
char *read_buffer[size];
首先,這些是分配有自動存盤持續時間的可變長度陣列。這也稱為“在堆疊上分配”。大多數作業系統對程式堆疊的大小都有不同的限制。在現代 Linux 中,這通常默認為 8MB(要檢查)。ulimit -s
使用給定的大小,您很容易在大多數機器上溢位堆疊。
其次,這些是指向字符的陣列,這意味著所需的空間乘以sizeof (char *),并且這些不是存盤以空字符結尾的字串的正確型別。
調高編譯器的警告級別應該已經提醒您注意第二個問題,警告如下
main.c:55:14: warning: passing argument 1 of ‘fill’ from incompatible pointer type [-Wincompatible-pointer-types]
55 | fill(write_buffer, size);
| ^~~~~~~~~~~~
| |
| char **
main.c:16:17: note: expected ‘char *’ but argument is of type ‘char **’
16 | void fill(char *bufptr, size_t size);
| ~~~~~~^~~~~~
同樣對于strlen.
第三,兩個緩沖區都存在于兩個行程中,其中每個行程只使用一個。
雖然這是一個玩具程式,但使用如此大的緩沖區是值得懷疑的。您正在處理非常簡單的固定長度訊息。寫入器寫入相同的位元組size - 1時間,然后是零位元組。閱讀器可以只消耗size位元組。
下一個問題是,在每個程序中,在內回圈的每次迭代中重復關閉管道的兩端。
讀取程序應該在外回圈之前關閉管道的寫入端一次。寫入程序應該在外回圈之前關閉管道的讀取端一次。
在回圈之后,兩個行程都應該關閉管道的一側。
您不檢查回傳值read或write確認沒有發生錯誤,或者預期要處理的資料量是否已完全完成。
fill是有缺陷的,盡管它的使用方式并不如此。
if (size != 0){
memset(bufptr, ch, size);
} else {
memset(bufptr, 'q', size);
}
bufptr[size-1] = '\0';
如果size為零:
memset(bufptr, 'q', size);實際上是NOP,沒有效果。bufptr[size-1] = '\0';將導致無符號整數溢位,并將索引陣列中的偏移量SIZE_MAX。
請注意,if (ch > 90)僅在使用后才檢查 ch。對于 ASCII,第 27 次使用此函式將產生一個包含[.
filled_count是相當沒有意義的。字串長度將為size - 1.
這是一個粗略的示例程式。
如果您有興趣分析一次處理單個位元組和處理更大緩沖區之間的差異,或者想要實際保留您處理的資料,并且想要重新引入字串緩沖區,請知道這char foo[size];實際上只適用于相對較小的值size. 您可以嘗試改用動態記憶體。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#define SIZES 6
#define KB 1024
/* 1KB, 10KB, 100KB, 1MB, 10MB, 100MB */
size_t PACK_SIZES[SIZES] = {1*KB, 10*KB, 100*KB, 1*KB*KB, 10*KB*KB, 100*KB*KB};
int PACK_TESTS[SIZES] = {6,5,4,3,2,1};
static void pdie(const char *msg) {
perror(msg);
exit(EXIT_FAILURE);
}
static char get_next_byte(void) {
static char byte = 'A';
if (byte > 'Z')
byte = 'A';
return byte ;
}
static int read_exactly(int fd, size_t size) {
unsigned char b;
while (size > 0 && 1 == read(fd, &b, 1))
size--;
return 0 == size;
}
static int write_exact_string(int fd, size_t size, char b) {
unsigned char zero = 0;
while (size > 1 && 1 == write(fd, &b, 1))
size--;
return (1 == size) && (1 == write(fd, &zero, 1));
}
int main(void) {
pid_t pid;
int pipefd[2];
if (-1 == pipe(pipefd))
pdie("pipe");
if (-1 == (pid = fork()))
pdie("fork");
if (0 == pid)
close(pipefd[1]);
else
close(pipefd[0]);
for (int i = 1; i <= SIZES; i ) {
size_t expected_size = PACK_SIZES[i];
int tests_amount = PACK_TESTS[i];
double total_time = 0;
for (int j = 1; j <= tests_amount; j ) {
clock_t start = clock();
if (pid == 0) {
if (!read_exactly(pipefd[0], expected_size)) {
fprintf(stderr, "Failed to read %zu bytes.\n", expected_size);
exit(EXIT_FAILURE);
}
} else {
char byte = get_next_byte();
if (!write_exact_string(pipefd[1], expected_size, byte)) {
fprintf(stderr, "Failed to write an exact string of [%zu*'%c' '\\0'].\n", expected_size - 1, byte);
exit(EXIT_FAILURE);
}
}
double duration = ((double) (clock() - start)) / CLOCKS_PER_SEC;
printf("Test<%d-%d>: %s %zu bytes in %f.\n", i, j, (pid == 0) ? "Read" : "Wrote", expected_size, duration);
total_time = duration;
}
printf("Time taken in <%s> to process %d * %zu bytes: %f (%f avg.)\n",
(pid == 0) ? "CHILD" : "PARENT",
tests_amount,
expected_size,
total_time,
total_time / tests_amount);
}
if (0 == pid) {
close(pipefd[0]);
} else {
close(pipefd[1]);
if (-1 == waitpid(pid, NULL, WUNTRACED))
pdie("waitpid");
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/485437.html
上一篇:fgets()沒有被執行
