Table of Contents for
Intermediate C Programming

Version ebook / Retour

Cover image for bash Cookbook, 2nd Edition Intermediate C Programming by Yung-Hsiang Lu Published by CRC Press, 2015
  1. Front Cover
  2. Contents (1/2)
  3. Contents (2/2)
  4. List of Figures (1/2)
  5. List of Figures (2/2)
  6. List of Tables
  7. Foreword
  8. Preface
  9. Author, Reviewers, and Artist
  10. Rules in Software Development
  11. Source Code
  12. I. Computer Storage: Memory and File
  13. 1. Program Execution (1/2)
  14. 1. Program Execution (2/2)
  15. 2. Stack Memory (1/5)
  16. 2. Stack Memory (2/5)
  17. 2. Stack Memory (3/5)
  18. 2. Stack Memory (4/5)
  19. 2. Stack Memory (5/5)
  20. 3. Prevent, Detect, and Remove Bugs (1/2)
  21. 3. Prevent, Detect, and Remove Bugs (2/2)
  22. 4. Pointers (1/6)
  23. 4. Pointers (2/6)
  24. 4. Pointers (3/6)
  25. 4. Pointers (4/6)
  26. 4. Pointers (5/6)
  27. 4. Pointers (6/6)
  28. 5. Writing and Testing Programs (1/4)
  29. 5. Writing and Testing Programs (2/4)
  30. 5. Writing and Testing Programs (3/4)
  31. 5. Writing and Testing Programs (4/4)
  32. 6. Strings (1/3)
  33. 6. Strings (2/3)
  34. 6. Strings (3/3)
  35. 7. Programming Problems and Debugging (1/4)
  36. 7. Programming Problems and Debugging (2/4)
  37. 7. Programming Problems and Debugging (3/4)
  38. 7. Programming Problems and Debugging (4/4)
  39. 8. Heap Memory (1/3)
  40. 8. Heap Memory (2/3)
  41. 8. Heap Memory (3/3)
  42. 9. Programming Problems Using Heap Memory (1/4)
  43. 9. Programming Problems Using Heap Memory (2/4)
  44. 9. Programming Problems Using Heap Memory (3/4)
  45. 9. Programming Problems Using Heap Memory (4/4)
  46. 10. Reading and Writing Files (1/3)
  47. 10. Reading and Writing Files (2/3)
  48. 10. Reading and Writing Files (3/3)
  49. 11. Programming Problems Using File (1/2)
  50. 11. Programming Problems Using File (2/2)
  51. II. Recursion
  52. 12. Recursion (1/4)
  53. 12. Recursion (2/4)
  54. 12. Recursion (3/4)
  55. 12. Recursion (4/4)
  56. 13. Recursive C Functions (1/4)
  57. 13. Recursive C Functions (2/4)
  58. 13. Recursive C Functions (3/4)
  59. 13. Recursive C Functions (4/4)
  60. 14. Integer Partition (1/5)
  61. 14. Integer Partition (2/5)
  62. 14. Integer Partition (3/5)
  63. 14. Integer Partition (4/5)
  64. 14. Integer Partition (5/5)
  65. 15. Programming Problems Using Recursion (1/5)
  66. 15. Programming Problems Using Recursion (2/5)
  67. 15. Programming Problems Using Recursion (3/5)
  68. 15. Programming Problems Using Recursion (4/5)
  69. 15. Programming Problems Using Recursion (5/5)
  70. III. Structure
  71. 16. Programmer-Defined Data Types (1/6)
  72. 16. Programmer-Defined Data Types (2/6)
  73. 16. Programmer-Defined Data Types (3/6)
  74. 16. Programmer-Defined Data Types (4/6)
  75. 16. Programmer-Defined Data Types (5/6)
  76. 16. Programmer-Defined Data Types (6/6)
  77. 17. Programming Problems Using Structure (1/4)
  78. 17. Programming Problems Using Structure (2/4)
  79. 17. Programming Problems Using Structure (3/4)
  80. 17. Programming Problems Using Structure (4/4)
  81. 18. Linked Lists (1/3)
  82. 18. Linked Lists (2/3)
  83. 18. Linked Lists (3/3)
  84. 19. Programming Problems Using Linked List (1/2)
  85. 19. Programming Problems Using Linked List (2/2)
  86. 20. Binary Search Trees (1/4)
  87. 20. Binary Search Trees (2/4)
  88. 20. Binary Search Trees (3/4)
  89. 20. Binary Search Trees (4/4)
  90. 21. Parallel Programming Using Threads (1/5)
  91. 21. Parallel Programming Using Threads (2/5)
  92. 21. Parallel Programming Using Threads (3/5)
  93. 21. Parallel Programming Using Threads (4/5)
  94. 21. Parallel Programming Using Threads (5/5)
  95. IV. Applications
  96. 22. Finding the Exit of a Maze (1/5)
  97. 22. Finding the Exit of a Maze (2/5)
  98. 22. Finding the Exit of a Maze (3/5)
  99. 22. Finding the Exit of a Maze (4/5)
  100. 22. Finding the Exit of a Maze (5/5)
  101. 23. Image Processing (1/3)
  102. 23. Image Processing (2/3)
  103. 23. Image Processing (3/3)
  104. 24. Huffman Compression (1/10)
  105. 24. Huffman Compression (2/10)
  106. 24. Huffman Compression (3/10)
  107. 24. Huffman Compression (4/10)
  108. 24. Huffman Compression (5/10)
  109. 24. Huffman Compression (6/10)
  110. 24. Huffman Compression (7/10)
  111. 24. Huffman Compression (8/10)
  112. 24. Huffman Compression (9/10)
  113. 24. Huffman Compression (10/10)
  114. A. Linux
  115. B. Version Control
  116. C. Integrated Development Environments (IDE) (1/3)
  117. C. Integrated Development Environments (IDE) (2/3)
  118. C. Integrated Development Environments (IDE) (3/3)
Parallel Programming Using Threads 345
// seq uential .c1
#in clude " subset s um .h "2
int subsetSum ( i n t * setA , i nt sizeA , in t kval )3
{4
unsigned int maxCode = 1;5
unsigned int ind ;6
for ( ind = 0; ind < sizeA ; ind ++)7
{8
maxCode *= 2;9
}10
int total = 0;11
for ( ind = 1; ind < maxCode ; ind ++)12
{13
total += s ubsetEqua l ( setA , sizeA , kval , ind );14
}15
return total ;16
}17
The function subsetEqual determines whether a specific subset sums to the value of k:
// su b setequal . c1
#in clude < stdio .h >2
int subsetE qual ( in t * setA , i nt sizeA , int kval ,3
unsigned int code )4
{5
int sum = 0;6
int ind = 0;7
unsigned int origcode = code ;8
while (( ind < sizeA ) && ( code > 0) )9
{10
i f (( code % 2) == 1)11
{12
sum += setA [ ind ];13
}14
ind ++;15
code >>= 1;16
}17
i f ( sum == kval )18
{19
printf (" equal : sum = %d , code = %X \n" ,20
sum , o rigcode ) ;21
return 1;22
}23
return 0;24
}25
21.4.3 Multi-Threaded Solution
The sequential program can be parallelized in a variety of ways. We need to figure out
how to distribute the work evenly across several threads. Each thread can be responsible for
checking the sums of some of the subsets. To be more precise, suppose a set has n elements
346 Intermediate C Programming
and t threads are used to solve the subset sum program (excluding the main thread). One
solution to distribute the work is to have the first thread check the subsets between 1 and
b
2
n
t
c. The second thread simultaneously checks the subsets between b
2
n
t
c + 1 and 2 × b
2
n
t
c.
It is important to handle the last thread with caution. If t is not a factor of 2
n
, then the
program must ensure that the thread includes the last set (value is 2
n
1).
The new subsetSum function contains three steps:
1. Create an object as the argument to each thread. This object contains multiple at-
tributes to a function. The attributes are put together into a single structure because
a thread can take only one argument. In this case, each object specifies the range
of subsets checked by the individual thread. The object includes (i) the range of the
subsets to be examined, (ii) the set, (iii) the set’s size, (iv) the value of k, and (v)
the number of subsets whose sums equal to k. It is necessary to give each thread all
relevant information because using global variables is strongly discouraged.
2. Create the threads. Each thread checks some subsets and computes the number of
subsets whose sums equal to k.
3. The main thread waits for every thread to complete and then adds the number subsets
that each thread reports.
The checkRange function is used by each thread, and is an argument of pthread create.
This is a SIMD program because the same function is used in every thread. Below is the
code listing for the subsetSum function using threads:
// thr eaddata .h1
#i f n d e f THREADD ATA_H2
#d ef in e THRE ADDATA_ H3
typedef s t ru ct4
{5
unsigned int minval ;6
unsigned int maxval ;7
int numSol ;8
int * setA ;9
int sizeA ;10
int kval ;11
} Thr e adData ;12
#e ndif13
// paralle l . c1
#in clude < pthread .h >2
#in clude < stdio .h >3
#in clude < stdlib .h >4
#in clude " thre a ddata . h"5
#in clude " subset s um .h "6
#d ef in e NUM B ER_THR EAD 167
void * c heckRange ( void * range )8
{9
ThreadD a ta * thd = ( ThreadD a ta *) range ;10
unsigned int minval = thd -> minval ;11
unsigned int maxval = thd -> maxval ;12
// printf (" minval = %d , maxval = %d \n" , minval , maxval );13
unsigned int ind ;14
// caution : need to use <= for max15
for ( ind = minval ; ind <= maxval ; ind ++)16
{17
Parallel Programming Using Threads 347
thd -> numSol +=18
subset Equal ( thd -> setA , thd -> sizeA ,19
thd -> kval , ind );20
}21
return NULL ;22
}23
24
int subsetSum ( i n t * setA , i nt sizeA , in t kval )25
// This function does not allocate memory ( malloc )26
// No need to free memory if failure occurs27
{28
29
pthread_t tid [ N UMBER_T HREAD ];30
ThreadD a ta thd [ NUM B ER_THR EAD ];31
// set the values for the thread data32
unsigned int maxCode = 1;33
unsigned int ind ;34
for ( ind = 0; ind < sizeA ; ind ++)35
{36
maxCode *= 2;37
}38
int total = 0;39
unsigned int minval = 1;40
unsigned int size = maxCode / NUMBE R_THREA D ;41
unsigned int maxval = size ;42
for ( ind = 0; ind < NUMB E R_THRE AD - 1; ind ++)43
{44
thd [ ind ]. minval = minval ;45
thd [ ind ]. maxval = maxval ;46
thd [ ind ]. numSol = 0;47
thd [ ind ]. setA = setA ;48
thd [ ind ]. sizeA = sizeA ;49
thd [ ind ]. kval = kval ;50
minval = maxval + 1;51
maxval += size ;52
}53
// ind should be NU MBER_TH READ - 1 now54
// handle the last thread diff e rently because55
// maxCode may not be a m ultiple of NU M BER_TH R EAD56
thd [ ind ]. minval = minval ;57
thd [ ind ]. maxval = maxCode - 1; // reme m b er -158
thd [ ind ]. numSol = 0;59
thd [ ind ]. setA = setA ;60
thd [ ind ]. sizeA = sizeA ;61
thd [ ind ]. kval = kval ;62
63
// create the threads64
for ( ind = 0; ind < NUMB E R_THRE AD ; ind ++)65
{66
int rtv ;67
rtv = p thread _creat e (& tid [ ind ] , NULL ,68
348 Intermediate C Programming
checkRange , ( void *) & thd [ ind ]) ;69
i f ( rtv != 0)70
{71
printf (" ERROR : pthr ead_cr a te () fail \n ");72
}73
}74
75
// wait for the threads to complete76
for ( ind = 0; ind < NUMB E R_THRE AD ; ind ++)77
{78
int rtv ;79
rtv = p thread_ join ( tid [ ind ] , NULL ) ;80
i f ( rtv != 0)81
{82
printf (" ERROR ; pthr ead_join () returns %d\ n" , rtv ) ;83
return EXIT _FAILUR E ;84
}85
total += thd [ ind ]. numSol ;86
}87
return total ;88
}89
There are a few details worth noting. First, the ranges checked by the threads must be
mutually exclusive. If one subset is checked by two or more threads and this subset’s sum
happens to equal to k, then this subset is counted multiple times and the total is wrong.
Second, the threads combined should check all subsets (excluding the empty set). Also,
checkRange needs to be consistent with the ranges assigned in subsetSum. In particular, if
checkRange uses <= maxval, then the maximum value checked by the last thread must be
maxCode - 1, not maxCode. You may notice that the individual threads share some data.
In each object, the attribute setA is a pointer to an array. This means that every thread
uses the same piece of memory. This is acceptable because the threads do not modify the
array. The other attributes are unique to each thread, because the object stores unshared
attributes (the int and unsigned int data).
21.5 Interleaving the Execution of Threads
The threads in the subset sum program shared a common array setA. Being able to share
memory between different threads is a characteristic of threaded programming; however, it
can sometimes be problematic. In the subset sum case, the threads never modify the shared
memory (i.e., setA), but only read the elements from the array. The only memory that the
threads modify is the attribute numSol, and each thread has a unique copy of this variable.
The main thread waits until all the threads are complete by calling pthread join on each
thread. Then the main thread adds the numSol values. The threads never intend to modify
any piece of shared memory. What happens if threads share memory that may be read and
written? The following listing is a simple and instructive example:
// outsync .c1
#in clude < pthread .h >2
#in clude < stdio .h >3
Parallel Programming Using Threads 349
#in clude < stdlib .h >4
#d ef in e NUM B ER_THR EAD 165
void * t hreadfunc ( void * arg )6
{7
int * intptr = ( in t *) arg ;8
while (1)9
{10
(* intptr ) ++;11
(* intptr ) --;12
i f ((* intptr ) != 0)13
{14
printf (" value is % d\n ", * intptr );15
return NULL ;16
}17
}18
return NULL ;19
}20
21
int main ( i n t argc , char * argv [])22
{23
pthread_t tid [ N UMBER_T HREAD ];24
int rtv ; // return value of pth r ead_cr eate25
int ind ;26
int arg = 0;27
for ( ind = 0; ind < NUMB E R_THRE AD ; ind ++)28
{29
rtv = p thread _creat e (& tid [ ind ] , NULL ,30
threadfunc , ( void *) & arg ) ;31
i f ( rtv != 0)32
{33
printf (" pth read_c reate () fail %d\ n" , rtv ) ;34
return EXIT _FAILUR E ;35
}36
}37
for ( ind = 0; ind < NUMB E R_THRE AD ; ind ++)38
{39
rtv = p thread_ join ( tid [ ind ] , NULL ) ;40
i f ( rtv != 0)41
{42
printf (" pth r ead_joi n () fail %d\ n" , rtv ) ;43
return EXIT _FAILUR E ;44
}45
}46
return EXIT _SUCCES S ;47
}48
This program creates some threads that share the address of the same integer variable
(arg in main). Each thread increments and decrements the value stored at that address
(i.e., the integer). If a thread finds that the value is not zero, then it prints a message and
terminates. Otherwise the thread will continue indefinitely. Can the threads ever print the
message? Will any thread return NULL and terminate? There is no good way to answer this