Koncno sem napisal svoj prvi multi-threaded programcek.
Sedaj rabim ljudi, ki bodo poiskali buge v tejle cudni reci.
Predvsem mi zaenkrat se vedno ni cisto jasno, kako
delujejo mutexi in conditioni.
Tistim, ki se sprasujete, ce je sploh potrebno komplicirati
s temi locki, predlagam, da jih odstranite in potem
pogledate, koliko % procesorja zre program brez lockov.
Programcek trenutno nima UI-ja, tako da je treba prilagoditve izvajati
kar v sourcu. V main se poigrajte z bdelay in tdelay.
Fora programcka je v tem, da bere s stdin, pise na stdout,
pri cemer se obnasa kot buffer.
Compilanje:
gcc buffer.c -lpthread -o buffer
Uporabna vrednost:
cat /dev/dsp | sox ( s parametri, ki jih ne poznam) | buffer | lame - test.mp3
To bi moralo dati lame-u dovolj velik buffer, da ne bi nehal s
kodiranjem samo zato, ker nek trenutek na stdin se ne bi bilo
podatkov (ce je masina hitra).
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/time.h>
#include <sys/types.h>
#define BUFSIZE 10000000
#define FRAMESIZE 500
char *membuf;
size_t membufdist; /* The No of chars between membufread
and membufwrite*/
char *membufread;
char *membufwrite;
pthread_mutex_t read_mutex, write_mutex, time_mutex;
int timer_locked;
pthread_cond_t read_cond, write_cond;
void timer(int * delay){
if (*delay >= 0){
pthread_mutex_unlock(&time_mutex);
pthread_mutex_lock(&time_mutex);
timer_locked = 1;
sleep(*delay);
pthread_mutex_unlock(&time_mutex);
// fprintf(stderr, "Unlock time! %i\n", membufdist);
timer_locked = 0;
pthread_cond_broadcast(&write_cond);
}
pthread_exit(NULL);
}
void write_thread(void * instuff){
int writesize, overflow, towrite;
while(!feof(stdout)){
if (timer_locked) {
pthread_mutex_lock(&time_mutex);
pthread_mutex_unlock(&time_mutex);
}
if (membufdist > 0) {
if (membufdist > FRAMESIZE) {
towrite = FRAMESIZE;
} else {
towrite = membufdist;
}
overflow = (membufwrite + towrite) - (membuf + BUFSIZE);
if (overflow < 0) overflow = 0;
writesize = fwrite((void*)membufwrite, 1, towrite - overflow,
stdout);
if (writesize <= 0) return;
if (overflow) {
membufdist = membufdist - writesize;
writesize = fwrite((void*)membuf, 1, overflow, stdout);
if (writesize < 0) return;
membufwrite = membuf + overflow;
} else {
membufwrite = membufwrite + writesize;
}
membufdist = membufdist - writesize;
if (membufdist < BUFSIZE){
pthread_cond_broadcast(&read_cond);
}
if (membufwrite == membuf + BUFSIZE) membufwrite = membuf;
} else {
}
}
}
void read_thread(int *delay){
int readsize;
int overflow;
int toread;
int eof = 0;
while (/* !eof */ !feof(stdin) || (membufdist > 0)){
if ((membufdist + FRAMESIZE) < BUFSIZE) {
toread = FRAMESIZE;
} else {
toread = BUFSIZE - membufdist;
}
if ((toread > 0) && (!feof(stdin))) {
overflow = (membufread + toread) - (membuf + BUFSIZE);
if (overflow < 0) overflow = 0;
readsize = fread((void*) membufread, 1, toread - overflow,
stdin);
if (overflow) {
membufdist = membufdist + readsize;
readsize = fread((void*) membufread, 1, toread -
overflow, stdin);
membufread = membuf + readsize;
} else {
membufread = membufread + readsize;
}
pthread_mutex_lock(&write_mutex);
membufdist = membufdist + readsize;
if (membufdist > 0){
pthread_cond_broadcast(&write_cond);
}
pthread_mutex_unlock(&write_mutex);
} else {
pthread_mutex_lock(&read_mutex);
while (membufdist >= BUFSIZE) {
pthread_mutex_lock(&write_mutex);
if (membufdist > 0){
pthread_cond_broadcast(&write_cond);
}
pthread_mutex_unlock(&write_mutex);
pthread_cond_wait(&read_cond, &read_mutex);
}
pthread_mutex_unlock(&read_mutex);
}
}
}
int main(){
pthread_t write_thr;
pthread_t timer_thr;
int tdelay, bdelay; /* delay timers - writing starts when either
the time delay expires or when the buffer
is filled with bdelay chars.
Setting them to a value < 0 is setting them to
infinity.
*/
membuf = (char*)malloc(BUFSIZE);
membufread = membuf;
membufwrite = membuf;
tdelay = 10;
bdelay = 0;
pthread_mutex_init(&time_mutex, NULL);
pthread_mutex_init(&read_mutex, NULL);
pthread_mutex_init(&write_mutex, NULL);
pthread_cond_init(&read_cond, NULL);
pthread_cond_init(&write_cond, NULL);
timer_locked = 0;
pthread_create(&write_thr, NULL, (void*)&write_thread, NULL);
pthread_create(&timer_thr, NULL, (void*)&timer, &tdelay);
read_thread(&bdelay);
return 0;
}