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