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;
}

Reply via email to