开发者

Trouble using fork() to calculate a total sum of received command line arguments

开发者 https://www.devze.com 2022-12-19 22:07 出处:网络
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 receive

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, w开发者_高级运维hich 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)


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.


Try this, if you want to change the pointers.

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

and

ChangePointers(&input, &output);


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

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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号