CSAPP笔记(十二) 并发编程

深入理解计算机系统

进程

地址空间独立,但数据共享困难。
IPC(进程间通信): 管道、存储器、信号量

void chld_handler(int sig){}
char* tfgets(char *s, int size, FILE *stream){
    fd_set read_set,ready_set;
    int left;
    Signal(SIGCHLD,chld_handler);
    pid_t pid;
    char *p = Mmap(0, size, PROT_WRITE,MAP_ANONYMOUS|MAP_SHARED, -1, 0);
    if((pid=Fork()) == 0){
        fgets(p, size, stream);
        exit(0);
    }
    left = Sleep(5);
    if (left == 0){
        Kill(pid,SIGKILL);
        return NULL;
    }else{
        Waitpid(pid,NULL,0);
        strcpy(s,p);
        return s;
    }
}

I/O多路复用

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

char* tfgets(char *s, int size, FILE *stream){
    fd_set read_set,ready_set;
    int nready;
    int fd = 0;
    FD_ZERO(&read_set);
    FD_SET(fd, &read_set);
    struct timeval tv;
    tv.tv_usec = 0;
    tv.tv_sec = 5;

    ready_set = read_set;
    // 阻塞
    nready = Select(fd+1, &ready_set, NULL, NULL, &tv);
    if (FD_ISSET(fd, &ready_set)) {
        fgets(s, size, stream);
        return s;
    }
    return NULL;
}

线程

int pthread_create(pthread_t thread, const pthread_attr_t *attr, void *(start_routine) (void ), void *arg);
pthread_t pthread_self();
int pthread_cancel(pthread_t thread);
void pthread_exit(void *retval);
int pthread_join(pthread_t thread, void **retval);
int pthread_detach(pthread_t thread);
int pthread_once(pthread_once_t *once_control, void (
init_routine)(void));
主线 pthread_exit会等子线程结束,pthread_once只执行一次,pthread_detach后不会被杀,死后由系统回收。

struct arg_struct{
    char *s;
    int size;
    FILE *stream;
    pthread_t tid;
};
void *TimeOut(void *t) {
    Sleep(*(int*)t);
    *(int*)t = 0;
}
void *doit(void *arg_struct){
    struct arg_struct *args = (struct arg_struct *)arg_struct;
    fgets(args->s,args->size,args->stream);
    pthread_cancel(args->tid);
}

char* tfgets(char *s, int size, FILE *stream){
    fd_set read_set,ready_set;
    int nready;
    int t = 5;
    FD_ZERO(&read_set);
    FD_SET(0, &read_set);
    pthread_t tid;
    Pthread_create(&tid,NULL,TimeOut,&t);
    struct arg_struct arg_struct;
    arg_struct.s = s;
    arg_struct.size = size;
    arg_struct.stream = stream;
    arg_struct.tid = tid;
    Pthread_create(&tid,NULL,doit,&arg_struct);
    Pthread_join(arg_struct.tid,NULL);
    return t==0?NULL:s;
}

信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
int sem_wait(sem_t *sem);//P
int sem_post(sem_t *sem);//V

生产者-消费者

缓冲区的槽位是动态变化

void sbuf_init(sbuf_t *sp, int n)
{
    sp->buf = Calloc(n, sizeof(int));
    sp->n = n;                       /* Buffer holds max of n items */
    sp->front = sp->rear = 0;        /* Empty buffer iff front == rear */
    Sem_init(&sp->mutex, 0, 1);      /* Binary semaphore for locking */
    Sem_init(&sp->slots, 0, n);      /* Initially, buf has n empty slots */
    Sem_init(&sp->items, 0, 0);      /* Initially, buf has zero data items */
}
void sbuf_insert(sbuf_t *sp, int item)
{
    P(&sp->slots);                          /* Wait for available slot */
    P(&sp->mutex);                          /* Lock the buffer */
    sp->buf[(++sp->rear)%(sp->n)] = item;   /* Insert the item */
    V(&sp->mutex);                          /* Unlock the buffer */
    V(&sp->items);                          /* Announce available item */
}
int sbuf_remove(sbuf_t *sp)
{
    int item;
    P(&sp->items);                          /* Wait for available item */
    P(&sp->mutex);                          /* Lock the buffer */
    item = sp->buf[(++sp->front)%(sp->n)];  /* Remove the item */
    V(&sp->mutex);                          /* Unlock the buffer */
    V(&sp->slots);                          /* Announce available slot */
    return item;
}

读者-写者

// 读者优先