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

时间:2010-02-06 20:30:18

标签: c unix fork

我正在尝试根据从命令行收到的数字组计算总和,我使用一个名为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(输入)= 8
  3. m = n / 2 = 4
  4. output = [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(输入)= 5
  10. m = n / 2 = 2
  11. output = [0 0]
  12. 我们分叉2个过程,先获得[3 7],第二个获得[11 7]
  13. 2个进程返回10,18,我们将其分配给输出。
  14. 输出有2个元素,因此我们为新输入分配2 + 1 = 3个元素的空间。
  15. 设置输入= [10 18 0]
  16. n = len(输入)= 3
  17. m = n / 2 = 1
  18. output = [0]
  19. 我们分叉一个进程,得到[10 18]
  20. 进程返回28,我们将其分配给输出。
  21. 输出有1个元素,所以我们完成了。
  22. 虽然在这个特定的数字集上我得到了:

    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)
    

4 个答案:

答案 0 :(得分:1)

您应该考虑编写一个函数,让我们称之为step_once()inputnoutput,并用{{1}写入相应的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(input)= 8
  3. m = n/2 = 4
  4. output = [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. 设置input = [3 7 11 7 0]
  9. n = len(input)= 5
  10. m = n/2 = 2
  11. output = [0 0]
  12. 我们分叉2个过程,先获得[3 7],第二个获得[11 7]
  13. 2个进程返回10,18,我们将其分配给output
  14. output有2个元素,因此我们为新的input分配2 + 1 = 3个元素的空间。
  15. 设置input = [10 18 0]
  16. n = len(input)= 3
  17. m = n/2 = 1
  18. output = [0]
  19. 我们分叉一个进程,得到[10 18]
  20. 流程返回28,我们将其分配给output
  21. 输出有1个元素,所以我们完成了。

答案 1 :(得分:0)

如果你想改变指针,试试这个。

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

ChangePointers(&amp; input,&amp; output);

答案 2 :(得分:0)

Ray,如果没有看到有关错误的更多详细信息,很难知道出了什么问题。如果我怀疑这些是运行时错误,您可以在valgrind下运行代码吗? valgrind在查明内存错误方面非常有效;与您的应用程序,你会想要

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

编辑:好的,有了valgrind错误,我们可以看到(a)你将狡猾的东西传递给printf(如果你使用-g进行编译,你将会得到确切的行号),你也在调用realloc但不是从malloc返回的指针。也许你已经完成了一些指针运算?

如果没有看到代码就说不出更多,但我希望你能找到valgrind很有帮助。

答案 3 :(得分:0)

你有几个一对一的错误:

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