SHOW:
|
|
- or go back to the newest paste.
1 | #include <stdlib.h> | |
2 | #include <stdio.h> | |
3 | #include <pthread.h> | |
4 | #include <errno.h> | |
5 | #include <string.h> | |
6 | #include <sys/types.h> | |
7 | #include <sys/stat.h> | |
8 | #include <fcntl.h> | |
9 | #include <unistd.h> | |
10 | #include <time.h> | |
11 | ||
12 | int thread_quantity; | |
13 | int buffer_size; | |
14 | char *requested_file_name; | |
15 | char *requested_word; | |
16 | ||
17 | int file_des = 0; | |
18 | int created_threads = 0; | |
19 | int alive_threads; | |
20 | ||
21 | pthread_mutex_t reading_mutex = PTHREAD_MUTEX_INITIALIZER; | |
22 | pthread_t *thread_id = NULL; | |
23 | off_t file_size; | |
24 | pthread_key_t buffer; | |
25 | ||
26 | void usage() { | |
27 | exit(1); | |
28 | } | |
29 | void err_exit(char *); | |
30 | void* thread_function(void *); | |
31 | void clean_thread(void *); | |
32 | void clean_tsd_buffer(void *); //thread specific data | |
33 | //############################################################ | |
34 | int main(int argc, char *argv[]) { | |
35 | int i; | |
36 | if (argc != 5) { | |
37 | usage(); | |
38 | } else { | |
39 | thread_quantity = (int) strtol(argv[1], NULL, 10); | |
40 | alive_threads = thread_quantity; | |
41 | thread_id = malloc(sizeof(pthread_t) * thread_quantity); | |
42 | requested_file_name = argv[2]; | |
43 | buffer_size = (int) strtol(argv[3], NULL, 10); | |
44 | if (errno) { | |
45 | usage(); | |
46 | } | |
47 | requested_word = argv[4]; | |
48 | } | |
49 | if ((file_des = open(requested_file_name, O_RDONLY)) == -1) { | |
50 | err_exit("Error: open(requested_file_name)"); | |
51 | } | |
52 | if ((file_size = lseek(file_des, 0, SEEK_END)) == (off_t) -1) { | |
53 | err_exit("Error: lseek(file_des, 0, SEEK_END)"); | |
54 | } | |
55 | if (lseek(file_des, 0, SEEK_SET) == (off_t) -1) { | |
56 | err_exit("Error: lseek(file_des, 0, SEEK_END)"); | |
57 | } | |
58 | if (pthread_mutex_init(&reading_mutex, NULL) != 0) { | |
59 | err_exit("Error: pthread_mutex_init(reading_mutex)"); | |
60 | } | |
61 | if (pthread_key_create(&buffer, clean_tsd_buffer)) { | |
62 | err_exit("Error: pthread_key_create()"); | |
63 | } | |
64 | //========================================================= | |
65 | for (i = 0; i < thread_quantity; i++) { | |
66 | if (pthread_create(&thread_id[i], NULL, thread_function, NULL)) { | |
67 | err_exit("Error: pthread_create()"); | |
68 | } else { | |
69 | created_threads++; | |
70 | } | |
71 | } | |
72 | while (alive_threads) { | |
73 | usleep(1000); | |
74 | } | |
75 | for (i = 0; i < thread_quantity; i++) { | |
76 | if (pthread_join(thread_id[i], NULL)) { | |
77 | err_exit("Error: pthread_join()"); | |
78 | } | |
79 | } | |
80 | //========================================================= | |
81 | err_exit(NULL); | |
82 | return EXIT_SUCCESS; | |
83 | } | |
84 | //############################################################ | |
85 | void clean_tsd_buffer(void *arg) { | |
86 | if (arg != NULL) { | |
87 | free(arg); | |
88 | } | |
89 | } | |
90 | void clean_thread(void *arg) { | |
91 | alive_threads--; | |
92 | } | |
93 | //----------------------------------------------------------- | |
94 | void *thread_function(void *data) { | |
95 | pthread_cleanup_push(clean_thread, NULL); | |
96 | if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) { | |
97 | err_exit("Error: pthread_setcanceltype()"); | |
98 | } | |
99 | if (pthread_setspecific(buffer, malloc(sizeof(char) * buffer_size))) { | |
100 | err_exit("Error: pthread_setspecific()"); | |
101 | } | |
102 | int i, bytes_readed; | |
103 | off_t jump, current_offset; | |
104 | void *cbuffer = pthread_getspecific(buffer); | |
105 | for (i = 0; i < thread_quantity; i++) { | |
106 | if (pthread_equal(pthread_self(), thread_id[i])) { | |
107 | jump = (off_t) i * buffer_size; | |
108 | break; | |
109 | } | |
110 | } | |
111 | //========================================================== | |
112 | while (1) { | |
113 | if (pthread_mutex_lock(&reading_mutex) != 0) { | |
114 | err_exit("Error: pthread_mutex_lock(reading_mutex)"); | |
115 | } | |
116 | if ((current_offset = lseek(file_des, jump, SEEK_SET)) == (off_t) -1) { | |
117 | err_exit("Error: lseek(reading_mutex)"); | |
118 | } | |
119 | if (current_offset > file_size) { | |
120 | if (pthread_mutex_unlock(&reading_mutex) != 0) { | |
121 | err_exit("Error: pthread_mutex_unlock(reading_mutex)"); | |
122 | } | |
123 | if (pthread_cancel(pthread_self())) { | |
124 | err_exit("Error: pthread_cancel()"); | |
125 | } | |
126 | } else { | |
127 | bytes_readed = read(file_des, cbuffer, buffer_size); | |
128 | } | |
129 | if (pthread_mutex_unlock(&reading_mutex) != 0) { | |
130 | err_exit("Error: pthread_mutex_unlock(reading_mutex)"); | |
131 | } | |
132 | usleep(50); | |
133 | if (bytes_readed > 0) { | |
134 | //no, don't need that code | |
135 | } else if (!bytes_readed) { | |
136 | if (pthread_cancel(pthread_self())) { | |
137 | err_exit("Error: pthread_cancel()"); | |
138 | } | |
139 | } else { // Error | |
140 | err_exit("Error: czytanie z pliku w wÄ…tku"); | |
141 | } | |
142 | jump += thread_quantity * buffer_size; | |
143 | } | |
144 | //========================================================== | |
145 | pthread_cleanup_pop(1); | |
146 | if (pthread_cancel(pthread_self())) { | |
147 | err_exit("Error: pthread_cancel()"); | |
148 | } | |
149 | return data; | |
150 | } | |
151 | //----------------------------------------------------------- | |
152 | void err_exit(char *msg) { | |
153 | if (msg != NULL) { | |
154 | perror(msg); | |
155 | sleep(10); | |
156 | } | |
157 | if (file_des != 0) { | |
158 | if (close(file_des) == -1) { | |
159 | perror("Error: close(file_des)"); | |
160 | } | |
161 | } | |
162 | if (thread_id != NULL) { | |
163 | free(thread_id); | |
164 | } | |
165 | exit(1); | |
166 | } | |
167 | ||
168 | ||
169 | ||
170 | ||
171 | ||
172 | ||
173 | /////////////////////////////////////####################### test.txt ################# | |
174 | The pthread_cleanup_push() function pushes routine onto the top of the | |
175 | stack of clean-up handlers. When routine is later invoked, it will be | |
176 | given arg as its clean argument. | |
177 | The pthread_cleanup_pop() function removes the routine at the top of | |
178 | the stack of clean-up handlers, and optionally executes it if execute | |
179 | is nonzero. | |
180 | ||
181 | A cancellation clean-up handler is popped from the stack and executed | |
182 | in the following circumstances: | |
183 | ||
184 | 1. When a thread is canceled, all of the stacked clean-up handlers are | |
185 | popped and executed in the reverse of the order in which they were | |
186 | pushed onto the stack. | |
187 | ||
188 | 2. When a thread terminates by calling pthread_exit(3), all clean-up | |
189 | handlers are executed as described in the preceding point. (Clean- | |
190 | up handlers are not called if the thread terminates by performing a | |
191 | return from the thread start function.) clean | |
192 | ||
193 | 3. When a thread calls pthread_cleanup_pop() with a nonzero execute | |
194 | argument, the top-mst clean-up handler is popped and executed. | |
195 | ||
196 | POSIX.1 permits pthread_cleanup_push() and pthread_cleanup_pop() to be | |
197 | implemented as macros that expand to text containing '{' and '}', | |
198 | respectively. For this reason, the caller must ensure that call |