Lab 3: Processes and Threads

  1. select()
    #include <stdio.h>
    #include <errno.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/select.h>
    
    #define FD_STDIN  0
    
    /*
     * Call read() would block the running process
     */
    void do_read(void) {
        int n;
        char buf[1024];
    
        while ((n = read(FD_STDIN, buf, sizeof(buf))) > 0) {
    	printf("%.*s", n, buf);
        }
    }
    
    /*
     * Call select() to probe for data before actually issuing read()
     */
    void do_select_then_read(void) {
        while (1) {
    	fd_set fds;
    	struct timeval timeout = { 1, 0 };  /* Timeout for 1 sec */
    
    	FD_ZERO(&fds);                      /* Initialize fds */
    	FD_SET(FD_STDIN, &fds);             /* Setup fds */
    
    	/* Call select() */
    	switch (select(FD_STDIN + 1, &fds, NULL, NULL, &timeout)) {
    	case -1:
    	    /* Error */
    	    fprintf(stderr, "Failed to call select(): %s\n", strerror(errno));
    	    break;
    	case 0:
    	    /* 
    	     * Timeout.  ie. no read input.
    	     * Some house keeping jobs can be done here!
    	     */
    	    printf("No input for 1 sec!\n");
    	    break;
    	default:
    	    /* 
    	     * Something is ready for read, use FD_ISSET() to check out
    	     * which one.
    	     */
    	    if (FD_ISSET(FD_STDIN, &fds)) {
    		int n;
    		char buf[1024];
    		
    		/* Now, go ahead and read it */
    		if ((n = read(FD_STDIN, buf, sizeof(buf))) > 0) {
    		    printf("%.*s", n, buf);
    		} else {
    		    return;
    		}
    	    }
    	    break;
    	}
        }
    }
    
    int main(void) {
        //do_read();
        do_select_then_read();
    
        return (1);
    }
    
  2. pthread library
    /*
     * % gcc thread.c -o thread -lpthread
     */
    
    #include <stdio.h>
    #include <pthread.h>
    
    #define N      4
    #define LOOP   1000
    
    /* A global mutex shared by all threads */
    pthread_mutex_t lock;
    /* A global variable protected by the mutex above */
    int counter = 0;
    
    /* 
     * A callback function assigned to a thread via pthread_create()
     */
    void *client(void *p) {
        int i, old, new;
    
        for (i = 0; i < LOOP; i++) {
    	pthread_mutex_lock(&lock);
    	old = counter;
    	new = ++counter;
    	pthread_mutex_unlock(&lock);
    
    	printf("Thread %d (%x): changed counter from %d to %d\n",
    	       (int)p, pthread_self(), old, new);
    	fflush(stdout);
        }
    
        return (NULL);
    }
    
    int main(void) {
        int i;
        pthread_t tid[N];
    
        /* Initialize the mutex before use */
        pthread_mutex_init(&lock, NULL);
    
        for (i = 0; i < N; i++) {
    	/* Create threads and assign client as callback functions */
    	pthread_create(&tid[i], NULL, client, (void *)i);
        }
    
        /* Wait for threads to exit */
        for (i = 0; i < N; i++) {
    	pthread_join(tid[i], NULL);
        }
    
        /* Destroy the mutext after use */
        pthread_mutex_destroy(&lock);
    
        return (0);
    }
    
  3. clone()
    #include <stdio.h>
    #include <sched.h>
    #include <errno.h>
    #include <string.h>
    
    #define STACK_SIZE  4096
    #define LOOP        1000
    
    /*
     * Callback function for clone()
     */
    int clone_callback(void *arg) {
        int i;
        for (i = 0; i < LOOP; i++) {
    	printf("%s: %d\n", (char *)arg, i);
        }
        return (0);
    }
    
    int main(void) {
        char stack1[STACK_SIZE];       /* Stack for 1st thread */
        char stack2[STACK_SIZE];       /* Stack for 2nd thread */
    
        /* Create 1st kernel thread */
        if (clone(clone_callback, stack1 + STACK_SIZE, CLONE_VM, "0") < 0) {
    	fprintf(stderr, "Failed to call clone(): %s\n", strerror(errno));
        }
    
        /* Create 2nd kernel thread */
        if (clone(clone_callback, stack2 + STACK_SIZE, CLONE_VM, "1") < 0) {
    	fprintf(stderr, "Failed to call clone(): %s\n", strerror(errno));
        }
    
        /* Sleep until the threads exit */
        sleep(10);
    
        return (0);
    }