使用 fork() 计算接收到的命令行参数的总和时出现问题

发布于 2024-08-21 01:07:04 字数 6384 浏览 2 评论 0原文

我正在尝试根据从命令行接收到的一组数字来计算总和,并且我使用一个名为worker的配套程序来为我进行计算。如果收到的数字数量是奇数,它将在数字数量上添加零以使该集合成为偶数。

这是程序的流程,以一种可以理解的方式(归功于 Alok):

一个例子会让这一点更清楚:

假设您想要添加 7 个数字: 1 2 3 4 5 6 7

./coordinator 1 2 3 4 5 6 7

  1. 输入 = [1 2 3 4 5 6 7 0]
  2. n = len(input) = 8
  3. m = n/2 = 4
  4. 输出 = [0 0 0 0]
  5. 我们分叉 4 个进程,第一个进程获取 [1 2],第二个进程获取[3 4], ...
  6. 4 个进程分别返回 3, 7, 11, 7,我们将其分配给输出。
  7. 输出有 4 个元素,因此我们为新输入分配 4+1 = 5 个元素的空间。
  8. 设置输入 = [3 7 11 7 0]
  9. n = len(input) = 5
  10. m = n/2 = 2
  11. 输出 = [0 0]
  12. 7]
  13. 我们分叉 2 个进程,第一个获取 [3 7],第二个获取 [ 11 2 个进程返回 10、18,我们将其分配给输出。
  14. 输出有 2 个元素,因此我们为新输入分配 2+1 = 3 个元素的空间。
  15. set input = [10 18 0]
  16. n = len(input) = 3
  17. m = n/2 = 1
  18. output = [0]
  19. 我们分叉一个进程,它得到 [10 18]
  20. 该进程返回 28,我们将其分配给输出。
  21. 输出有 1 个元素,所以我们完成了。

尽管在这组特定的数字上我得到:

Process ID: 15195 
Sum of 1 and 2 is 3 

Process ID: 15196 
Sum of 3 and 4 is 7 

Process ID: 15197 
Sum of 5 and 6 is 11 

Process ID: 15198 
Sum of 7 and 0 is 7 

*** glibc detected *** ./coordinator: free(): invalid next size (fast): 0x080ec048 ***

后面是堆错误列表。

我相信我没有正确重新分配指针的大小,在第一次调用 next_step() 之后我尝试将旧输出重定向到新输入。所以它试图将数据放入内存中没有空间的部分。

更新:

@Norman

这是我收到的输出:

==3585== Memcheck, a memory error detector
==3585== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3585== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3585== Command: ./coordinator 1 2 3 4
==3585== 
calc: 2:
input[0]: 1
input[1]: 2
input[2]: 3
input[3]: 4
==3585== Use of uninitialised value of size 4
==3585==    at 0x4076186: ??? (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4079A81: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x407618E: ??? (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4079A81: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x4077877: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x407789B: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
input[4]: 0
==3586== Memcheck, a memory error detector
==3586== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3586== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3586== Command: ./worker 1 2
==3586== 
Process ID: 3586 
Sum of 1 and 2 is 3 

==3586== 
==3586== HEAP SUMMARY:
==3586==     in use at exit: 0 bytes in 0 blocks
==3586==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3586== 
==3586== All heap blocks were freed -- no leaks are possible
==3586== 
==3586== For counts of detected and suppressed errors, rerun with: -v
==3586== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3587== Memcheck, a memory error detector
==3587== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3587== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3587== Command: ./worker 3 4
==3587== 
Process ID: 3587 
Sum of 3 and 4 is 7 

==3587== 
==3587== HEAP SUMMARY:
==3587==     in use at exit: 0 bytes in 0 blocks
==3587==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3587== 
==3587== All heap blocks were freed -- no leaks are possible
==3587== 
==3587== For counts of detected and suppressed errors, rerun with: -v
==3587== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3585== Invalid write of size 4
==3585==    at 0x8048A3A: main (in /home/bryan/cpp/coordinator)
==3585==  Address 0x417f0b4 is 8 bytes after a block of size 4 alloc'd
==3585==    at 0x4024C6C: malloc (vg_replace_malloc.c:195)
==3585==    by 0x4024CF6: realloc (vg_replace_malloc.c:476)
==3585==    by 0x8048A25: main (in /home/bryan/cpp/coordinator)
==3585== 
==3588== Memcheck, a memory error detector
==3588== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3588== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3588== Command: ./worker 3 7
==3588== 
Process ID: 3588 
Sum of 3 and 7 is 10 

==3588== 
==3588== HEAP SUMMARY:
==3588==     in use at exit: 0 bytes in 0 blocks
==3588==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3588== 
==3588== All heap blocks were freed -- no leaks are possible
==3588== 
==3588== For counts of detected and suppressed errors, rerun with: -v
==3588== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3585== Invalid read of size 4
==3585==    at 0x8048AB5: main (in /home/bryan/cpp/coordinator)
==3585==  Address 0x417f0e0 is 0 bytes after a block of size 0 alloc'd
==3585==    at 0x4024C6C: malloc (vg_replace_malloc.c:195)
==3585==    by 0x4024CF6: realloc (vg_replace_malloc.c:476)
==3585==    by 0x8048A77: main (in /home/bryan/cpp/coordinator)
==3585== 
The final sum is: 0==3585== 
==3585== HEAP SUMMARY:
==3585==     in use at exit: 28 bytes in 2 blocks
==3585==   total heap usage: 4 allocs, 2 frees, 32 bytes allocated
==3585== 
==3585== LEAK SUMMARY:
==3585==    definitely lost: 8 bytes in 1 blocks
==3585==    indirectly lost: 0 bytes in 0 blocks
==3585==      possibly lost: 20 bytes in 1 blocks
==3585==    still reachable: 0 bytes in 0 blocks
==3585==         suppressed: 0 bytes in 0 blocks
==3585== Rerun with --leak-check=full to see details of leaked memory
==3585== 
==3585== For counts of detected and suppressed errors, rerun with: -v
==3585== Use --track-origins=yes to see where uninitialised values come from
==3585== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 11 from 6)

I'm trying to calculate the sum based off of sets of numbers received from the command line and I use a companion program called worker to due the computation for me. If the amount of numbers received is odd, it will add a zero to the amount of numbers to make the set even.

This is the flow of the program in an understandable way(credit to Alok):

An example will make this clearer:

Let's say you want to add 7 numbers: 1 2 3 4 5 6 7

./coordinator 1 2 3 4 5 6 7

  1. input = [1 2 3 4 5 6 7 0]
  2. n = len(input) = 8
  3. m = n/2 = 4
  4. output = [0 0 0 0]
  5. We fork 4 process, first process gets [1 2], second gets [3 4], ...
  6. The 4 processes return 3, 7, 11, 7 respectively, which we assign to output.
  7. output has 4 elements, so we allocate space for 4+1 = 5 elements for the new input.
  8. set input = [3 7 11 7 0]
  9. n = len(input) = 5
  10. m = n/2 = 2
  11. output = [0 0]
  12. We fork 2 processes, first gets [3 7], second gets [11 7]
  13. The 2 processes return 10, 18, which we assign to output.
  14. output has 2 elements, so we allocate space for 2+1 = 3 elements for the new input.
  15. set input = [10 18 0]
  16. n = len(input) = 3
  17. m = n/2 = 1
  18. output = [0]
  19. We fork one process, which gets [10 18]
  20. The process returns 28, which we assign to output.
  21. output has 1 element, so we are done.

Although on this particular set of numbers I get:

Process ID: 15195 
Sum of 1 and 2 is 3 

Process ID: 15196 
Sum of 3 and 4 is 7 

Process ID: 15197 
Sum of 5 and 6 is 11 

Process ID: 15198 
Sum of 7 and 0 is 7 

*** glibc detected *** ./coordinator: free(): invalid next size (fast): 0x080ec048 ***

Followed by a list of heap errors.

I believe I am not reallocating the size of the pointers correctly in which I attempt to redirect the old output to the new input after the first call to next_step(). So it's trying to put data into a part of memory for which there is no space.

UPDATE:

@Norman

This is the output I receive:

==3585== Memcheck, a memory error detector
==3585== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3585== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3585== Command: ./coordinator 1 2 3 4
==3585== 
calc: 2:
input[0]: 1
input[1]: 2
input[2]: 3
input[3]: 4
==3585== Use of uninitialised value of size 4
==3585==    at 0x4076186: ??? (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4079A81: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x407618E: ??? (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4079A81: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x4077877: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
==3585== Conditional jump or move depends on uninitialised value(s)
==3585==    at 0x407789B: vfprintf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x4080F7F: printf (in /lib/tls/i686/cmov/libc-2.10.1.so)
==3585==    by 0x8048833: main (in /home/bryan/cpp/coordinator)
==3585== 
input[4]: 0
==3586== Memcheck, a memory error detector
==3586== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3586== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3586== Command: ./worker 1 2
==3586== 
Process ID: 3586 
Sum of 1 and 2 is 3 

==3586== 
==3586== HEAP SUMMARY:
==3586==     in use at exit: 0 bytes in 0 blocks
==3586==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3586== 
==3586== All heap blocks were freed -- no leaks are possible
==3586== 
==3586== For counts of detected and suppressed errors, rerun with: -v
==3586== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3587== Memcheck, a memory error detector
==3587== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3587== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3587== Command: ./worker 3 4
==3587== 
Process ID: 3587 
Sum of 3 and 4 is 7 

==3587== 
==3587== HEAP SUMMARY:
==3587==     in use at exit: 0 bytes in 0 blocks
==3587==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3587== 
==3587== All heap blocks were freed -- no leaks are possible
==3587== 
==3587== For counts of detected and suppressed errors, rerun with: -v
==3587== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3585== Invalid write of size 4
==3585==    at 0x8048A3A: main (in /home/bryan/cpp/coordinator)
==3585==  Address 0x417f0b4 is 8 bytes after a block of size 4 alloc'd
==3585==    at 0x4024C6C: malloc (vg_replace_malloc.c:195)
==3585==    by 0x4024CF6: realloc (vg_replace_malloc.c:476)
==3585==    by 0x8048A25: main (in /home/bryan/cpp/coordinator)
==3585== 
==3588== Memcheck, a memory error detector
==3588== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==3588== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==3588== Command: ./worker 3 7
==3588== 
Process ID: 3588 
Sum of 3 and 7 is 10 

==3588== 
==3588== HEAP SUMMARY:
==3588==     in use at exit: 0 bytes in 0 blocks
==3588==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==3588== 
==3588== All heap blocks were freed -- no leaks are possible
==3588== 
==3588== For counts of detected and suppressed errors, rerun with: -v
==3588== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 6)
==3585== Invalid read of size 4
==3585==    at 0x8048AB5: main (in /home/bryan/cpp/coordinator)
==3585==  Address 0x417f0e0 is 0 bytes after a block of size 0 alloc'd
==3585==    at 0x4024C6C: malloc (vg_replace_malloc.c:195)
==3585==    by 0x4024CF6: realloc (vg_replace_malloc.c:476)
==3585==    by 0x8048A77: main (in /home/bryan/cpp/coordinator)
==3585== 
The final sum is: 0==3585== 
==3585== HEAP SUMMARY:
==3585==     in use at exit: 28 bytes in 2 blocks
==3585==   total heap usage: 4 allocs, 2 frees, 32 bytes allocated
==3585== 
==3585== LEAK SUMMARY:
==3585==    definitely lost: 8 bytes in 1 blocks
==3585==    indirectly lost: 0 bytes in 0 blocks
==3585==      possibly lost: 20 bytes in 1 blocks
==3585==    still reachable: 0 bytes in 0 blocks
==3585==         suppressed: 0 bytes in 0 blocks
==3585== Rerun with --leak-check=full to see details of leaked memory
==3585== 
==3585== For counts of detected and suppressed errors, rerun with: -v
==3585== Use --track-origins=yes to see where uninitialised values come from
==3585== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 11 from 6)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

灼痛 2024-08-28 01:07:04

您应该考虑编写一个函数,我们将其称为 step_once(),它将接受带有 n 个数字的 input,并写入相应的 < code>output 与 m = n/2 元素。上面的 n 是输入数字的数量 + 1,input 的最后一个元素等于 0。

在您的驱动程序函数中,假设 main():如果 output 包含 1 个数字,则完成。否则,您将重新分配input以包含n_new = m+1元素,重新分配output以包含m_new = n_new/2 > 元素,并再次调用函数 step_once()。继续执行此操作,直到获得一个数字:

function next_step(input, output, n, m):
    n := number of input numbers # this is 1 greater than
                                 # the number of numbers being summed
    m := n / 2 # C division
    n_children := m
    i := 0
    while i < m:
        fork worker with input[2*i] and input[2*i+1]
        get result in output[i]
        i := i + 1

function main:
    set n := length(input) + 1
    set m := n/2
    allocate memory for input # n+1 elements, last = 0
    allocate memory for output # m elements
    set values in input
    while True:
        next_step(input, output, n, m)
        if length or output == 1:
             done, return
        else:
            set n := length(output) + 1
            set m := n/2
            allocate space for new_input # n elements
            set new_input := output + [0]
            free input and output
            set input := new_input
            allocate memory for output # m elements

优点是您可以测试 next_step() 函数以确保其正常工作,从而使调试更容易。

举个例子可以让这一点更清楚:

假设您要添加 7 个数字: 1 2 3 4 5 6 7

  1. input = [1 2 3 4 5 6 7 0]
  2. n = len(输入) = 8
  3. m = n/2 = 4
  4. 输出 = [0 0 0 0]
  5. 我们分叉 4 个进程,第一个进程获取 [1 2],第二个进程获取 [3 4],...
  6. 这 4 个进程分别返回 3、7、11、7,我们将其分配给 output
  7. output 有 4 个元素,因此我们为新的 input 分配 4+1 = 5 个元素的空间。
  8. 设置输入 = [3 7 11 7 0]
  9. n = len(输入) = 5
  10. m = >n/2 = 2
  11. output = [0 0]
  12. 我们分叉 2 个进程,第一个获取 [3 7],第二个获取 [11 7]
  13. 这 2 个进程返回 10, 18,其中我们分配给输出
  14. output 有 2 个元素,因此我们为新的 input 分配 2+1 = 3 个元素的空间。
  15. 设置输入 = [10 18 0]
  16. n = len(输入) = 3
  17. m = n /2 = 1
  18. output = [0]
  19. 我们分叉一个进程,它得到 [10 18]
  20. 该进程返回 28,我们将其分配给 output
  21. 输出有 1 个元素,所以我们完成了。

You should think about writing a function, let's call it step_once(), which will take input with n numbers, and write to the corresponding output with m = n/2 elements. n above is the number of input numbers + 1, with the last element of input equal to 0.

In your driver function, let's say main(): if output contains 1 number, you are done. Otherwise, you reallocate input to contain n_new = m+1 elements, reallocate output to contain m_new = n_new/2 elements, and call the function step_once() again. You keep doing this until you get one number:

function next_step(input, output, n, m):
    n := number of input numbers # this is 1 greater than
                                 # the number of numbers being summed
    m := n / 2 # C division
    n_children := m
    i := 0
    while i < m:
        fork worker with input[2*i] and input[2*i+1]
        get result in output[i]
        i := i + 1

function main:
    set n := length(input) + 1
    set m := n/2
    allocate memory for input # n+1 elements, last = 0
    allocate memory for output # m elements
    set values in input
    while True:
        next_step(input, output, n, m)
        if length or output == 1:
             done, return
        else:
            set n := length(output) + 1
            set m := n/2
            allocate space for new_input # n elements
            set new_input := output + [0]
            free input and output
            set input := new_input
            allocate memory for output # m elements

The advantage is that you can test your next_step() function to make sure it works and thus makes debugging easier.

An example will make this clearer:

Let's say you want to add 7 numbers: 1 2 3 4 5 6 7

  1. input = [1 2 3 4 5 6 7 0]
  2. n = len(input) = 8
  3. m = n/2 = 4
  4. output = [0 0 0 0]
  5. We fork 4 process, first process gets [1 2], second gets [3 4], ...
  6. The 4 processes return 3, 7, 11, 7 respectively, which we assign to output.
  7. output has 4 elements, so we allocate space for 4+1 = 5 elements for the new input.
  8. set input = [3 7 11 7 0]
  9. n = len(input) = 5
  10. m = n/2 = 2
  11. output = [0 0]
  12. We fork 2 processes, first gets [3 7], second gets [11 7]
  13. The 2 processes return 10, 18, which we assign to output.
  14. output has 2 elements, so we allocate space for 2+1 = 3 elements for the new input.
  15. set input = [10 18 0]
  16. n = len(input) = 3
  17. m = n/2 = 1
  18. output = [0]
  19. We fork one process, which gets [10 18]
  20. The process returns 28, which we assign to output.
  21. output has 1 element, so we are done.
各自安好 2024-08-28 01:07:04

如果您想更改指针,请尝试此操作。

void ChangePointers(int **input, int **output)

ChangePointers(&input, &output);

Try this, if you want to change the pointers.

void ChangePointers(int **input, int **output)

and

ChangePointers(&input, &output);

多孤肩上扛 2024-08-28 01:07:04

您有几个相差一的错误:

  1. for(i = 0; i < argc; i++)
  2. while(calc > 0)

You have a couple of off-by-one errors:

  1. for(i = 0; i < argc; i++)
  2. while(calc > 0)
所谓喜欢 2024-08-28 01:07:04

Ray,如果不查看有关错误的更多详细信息,很难知道出了什么问题。如果正如我怀疑的那样,这些是运行时错误,您可以在 valgrindvalgrind 在查明内存错误方面非常有效;在您的应用程序中,您需要

valgrind --trace-children=yes ./coordinator 1 2 3 4

编辑:好的,通过 valgrind 错误,我们可以看到 (a) 您向 printf 传递了一些狡猾的东西(如果您使用 < code>-g 你会得到准确的行号),而且你正在调用 realloc 但不是在从 malloc 返回的指针上调用。也许你已经做过一些指针算术?

在没有看到代码的情况下不能说更多,但我希望 valgrind 对您有所帮助。

Ray, it's hard to know what's wrong without seeing more details about the errors. If, as I suspect, these are run-time errors, can you run the code under valgrind? valgrind is extremely effective at pinpointing memory errors; with your application you'll want

valgrind --trace-children=yes ./coordinator 1 2 3 4

EDIT: OK, with the valgrind errors we can see that (a) you're passing something dodgy to printf (if you compile with -g you'll get the exact line number), and also you're calling realloc but not on a pointer you got back from malloc. Maybe you've done some pointer arithmetic?

Can't say more without seeing the code, but I hope you find valgrind helpful.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文