1 /* BeginSourceFile quicksort.c
3 This file is take from the DDE test system. It spawns six
4 threads to do a sort of an array of random numbers.
6 The locations marked "quick N" are used in the test "quicksort.exp".
8 The locations marked "att N" are used in the test "attach.exp".
12 cc -Ae +DA1.0 -g -o quicksort -lpthread quicksort.c
16 quicksort --normal run
17 quicksort 1 --waits before starting to allow attach
28 #define SORTSET 100000
30 /* Uncomment to turn on debugging output */
31 /* #define QUICK_DEBUG */
33 /* Uncomment to turn on wait on each thread create */
34 /* #define THREAD_WAIT */
36 /* Fewer than SORT_DIRECT items are sorted with an insertion sort. */
37 #define SORT_DIRECT 20
39 /* Work at this depth or less generates a separate work item. */
42 /* Workpile controller */
43 typedef void (*work_proc_t
)(void *);
45 typedef struct workpile_struct
{
46 pthread_mutex_t lock
; /* mutex for this structure */
47 pthread_cond_t work_wait
; /* workers waiting for work */
48 pthread_cond_t finish_wait
; /* to wait for workers to finish */
49 int max_pile
; /* length of workpile array */
50 work_proc_t worker_proc
; /* work procedure */
51 int n_working
; /* number of workers working */
52 int n_waiting
; /* number of workers waiting for work */
53 int n_pile
; /* number of pointers in the workpile */
54 int inp
; /* FIFO input pointer */
55 int outp
; /* FIFO output pointer */
56 void *pile
[1]; /* array of pointers - the workpile */
60 float *data
; /* Array to sort */
61 int n
; /* Number of elements in the array */
62 int depth
; /* Depth of recursion */
63 workpile_t wp
; /* Workpile to use */
66 /* True if waiting for attach.
68 int wait_here
= FALSE
;
70 static workpile_t quick_sort_workpile
= NULL
;
72 void *worker(void * wptr
);
74 /* Allocates and initializes a workpile that holds max_pile entries.
75 * worker_proc is called to process each work item on the queue.
78 work_init(int max_pile
, work_proc_t worker_proc
, int n_threads
)
82 workpile_t wp
= (workpile_t
)
83 malloc(sizeof (struct workpile_struct
) +
84 (max_pile
* sizeof (void *)));
87 pthread_mutex_init(&wp
->lock
, NULL
);
88 pthread_cond_init(&wp
->work_wait
, NULL
);
89 pthread_cond_init(&wp
->finish_wait
, NULL
);
90 wp
->max_pile
= max_pile
;
91 wp
->worker_proc
= worker_proc
;
92 wp
->n_working
= wp
->n_waiting
= wp
->n_pile
= 0;
93 wp
->inp
= wp
->outp
= 0;
95 err
= pthread_create(&t
, NULL
,
98 printf( "== Quicksort: created new thread\n" );
100 if( n_threads
> 0 ) {
102 printf( "== Quicksort: waiting on user input of an integer\n" );
104 printf( "== Quicksort: continuing with quicksort\n" );
109 assert(err
== 0); /* quick 1 */
111 /* All the threads have now been created.
113 assert( n_threads
== -1 ); /* att 1 */
116 printf( "== Quicksort: waiting for attach\n" );
120 wait_here
= 99; /* att 2, otherwise useless */
122 return (wp
); /* quick 2 */
126 * Worker thread routine. Continuously looks for work, calls the
127 * worker_proc associated with the workpile to do work.
135 wp
= * (workpile_t
*) wptr
;
137 pthread_mutex_lock(&wp
->lock
);
140 while (wp
->n_pile
== 0) { /* wait for new work */
141 if (--wp
->n_working
== 0)
142 pthread_cond_signal(&wp
->finish_wait
);
144 pthread_cond_wait(&wp
->work_wait
, &wp
->lock
);
145 wp
->n_waiting
--; /* quick 3 */
149 ptr
= wp
->pile
[wp
->outp
];
150 wp
->outp
= (wp
->outp
+ 1) % wp
->max_pile
;
151 pthread_mutex_unlock(&wp
->lock
);
152 /* Call application worker routine. */
153 (*wp
->worker_proc
)(ptr
);
154 pthread_mutex_lock(&wp
->lock
); /* quick 4 */
159 /* Puts ptr in workpile. Called at the outset, or within a worker. */
161 work_put(workpile_t wp
, void *ptr
)
163 pthread_mutex_lock(&wp
->lock
);
165 /* idle workers to be awakened */
166 pthread_cond_signal(&wp
->work_wait
);
168 assert(wp
->n_pile
!= wp
->max_pile
); /* check for room */
170 wp
->pile
[wp
->inp
] = ptr
;
171 wp
->inp
= (wp
->inp
+ 1) % wp
->max_pile
;
172 pthread_mutex_unlock(&wp
->lock
);
176 /* Wait until all work is done and workers quiesce. */
178 work_wait(workpile_t wp
)
180 pthread_mutex_lock(&wp
->lock
);
181 while(wp
->n_pile
!=0 || wp
->n_working
!= 0)
182 pthread_cond_wait(&wp
->finish_wait
, &wp
->lock
);
183 pthread_mutex_unlock(&wp
->lock
);
187 quick_sort_aux(float *data
, int n
, int depth
, workpile_t wp
, int deferrable
)
191 /* If array small, use insertion sort */
192 if (n
<= SORT_DIRECT
) {
193 for (j
= 1; j
< n
; j
++) {
194 /* data[0..j-1] in sort; find a spot for data[j] */
196 for (i
= j
- 1; i
>= 0 && key
< data
[i
]; i
--)
202 /* Defer this work to work queue if policy says so */
203 if (deferrable
&& depth
<= DEFER_DEPTH
) {
204 quick_sort_args
*q
= (quick_sort_args
*)
205 malloc(sizeof (quick_sort_args
));
207 q
->data
= data
; q
->n
= n
; q
->depth
= depth
; q
->wp
= wp
;
208 work_put(wp
, (void *)q
);
211 /* Otherwise, partition data based on a median estimate */
212 #define swap(i,j) {float t = data[i]; data[i] = data[j]; data[j] = t;}
216 while (data
[i
] < data
[j
]) j
--;
219 while (data
[i
] < data
[j
]) i
++;
220 if (i
>= j
) { i
= j
; break; }
223 /* Median value is now at data[i] */
224 /* Partitioned so that data[0..i-1] <= median <= data[i+1..n-1] */
225 quick_sort_aux(data
, i
, depth
+1, wp
, TRUE
);
226 quick_sort_aux(&data
[i
+1], n
-i
-1, depth
+1, wp
, TRUE
);
228 /* Called from workpile controller with argument pointing to work. */
230 quick_sort_worker(void *a
)
232 quick_sort_args
*q
= (quick_sort_args
*)a
;
233 quick_sort_aux(q
->data
, q
->n
, q
->depth
, q
->wp
, FALSE
);
236 /* Main routine, called by client to do a sort. */
238 quick_sort(float *data
, int n
)
240 if (quick_sort_workpile
== NULL
) {
242 quick_sort_workpile
= work_init(2 << DEFER_DEPTH
,
243 quick_sort_worker
, n_threads
);
244 assert(quick_sort_workpile
!= NULL
);
247 quick_sort_aux(data
, n
, 0, quick_sort_workpile
, FALSE
);
249 /* Wait for all work to finish */
250 work_wait(quick_sort_workpile
);
253 printf( "== Quicksort: done sorting\n" );
263 int i
; int debugging
= 0;
265 if((argc
> 1) && (0 != argv
)) {
266 if( 1 == atoi( argv
[1] ) )
270 for(i
= 0; i
< SORTSET
; i
++)
271 data
[SORTSET
-1 -i
] = drand48();
273 for(i
= 0; i
< SORTSET
; i
++)
275 printf("data[%d] = %f\n", i
, data
[i
]);
277 quick_sort(data
, SORTSET
);
278 for(i
= 0; i
< SORTSET
; i
++)
280 printf("data[%d] = %f\n", i
, data
[i
]);