UNP函数笔记十六: 线程

58 篇文章 0 订阅
49 篇文章 0 订阅

第二十六章  线程:

#include <pthread.h>
int pthread_create(pthread_t * tid, 
                   const pthread_attr_t * attr, 
                   void * (*func)(void *), void * arg);
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
int pthread_join(pthread_t tid, void ** status);
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
pthread_t pthread_self(void);

#include <pthread.h>
int pthread_detach(pthread_t tid);
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
void pthread_exit(void * status);

#include <pthread.h>
pthread_once_t once = PTHREAD_ONCE_INIT;
int pthread_once(pthread_once_t * onceptr, void (*init)(void));
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
int pthread_key_create(pthread_key_t * keyptr, 
                       void (*destructor)(void * value));
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
void * pthread_getspecific(pthread_key_t key);
    return thread private data, no data match with key return NULL
int pthread_setspecific(pthread_key_t key, const void * value);
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
int pthread_mutex_lock(pthread_mutex_t * mptr);
    success return 0, error return Exxx, will not modify errno
int pthread_mutex_unlock(pthread_mutex_t * mptr);
    success return 0, error return Exxx, will not modify errno

#include <pthread.h>
int pthread_cond_wait(pthread_cond_t * cptr, 
                      pthread_mutex_t * mptr);
    success return 0, error return Exxx, will not modify errno
int pthread_cond_signal(pthread_cond_t * cptr);
    success return 0, error return Exxx, will not modify errno

PTHREAD_COND_INITIALIZER

#include <pthread.h>
int pthread_cond_broadcast(pthread_cond_t * cptr);
    success return 0, error return Exxx, will not modify errno
int pthread_cond_timedwait(pthread_cond_t * cptr, 
                           pthread_mutex_t * mptr, 
                           const struct timespec * abstime);
    success return 0, error return Exxx, will not modify errno
    struct timespec {
        time_t    tv_sec;  /* seconds */
        long      tv_nsec; /* nanosecods */
    };

示例:

#ifndef __WARP_FUNCTION_H__
#define __WARP_FUNCTION_H__


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/socket.h>

#ifndef MAXLINE
#define MAXLINE 4096
#endif

void err_msg(const char * msg, int error)
{
    printf("%s : %s\n", msg, strerror(error));
    exit(1);
}

int Pthread_create(pthread_t * tid, 
                   const pthread_attr_t * attr, 
                   void * (*func)(void *), void * arg)
{
    int error = pthread_create(tid, attr, func, arg);
    if (error != 0) {
        err_msg("pthread_create error", error);
    }
    return(error);
}

int Pthread_join(pthread_t tid, void ** status)
{
    int error = pthread_join(tid, status);
    if (error != 0) {
        err_msg("pthread_join error", error);
    }
    return(error);
}

pthread_t Pthread_self(void)
{
    return(pthread_self());
}

int Pthread_detach(pthread_t tid)
{
    int error = pthread_detach(tid);
    if (error != 0) {
        err_msg("pthread_detach error", error);
    }
    return(error);
}

void Pthread_exit(void * status)
{
    pthread_exit(status);
}

int Pthread_once(pthread_once_t * onceptr, void (*init)(void))
{
    int error = pthread_once(onceptr, init);
    if (error != 0) {
        err_msg("pthread_once error", error);
    }
    return(error);
}

int Pthread_key_create(pthread_key_t * keyptr, 
                       void (*destructor)(void * value))
{
    int error = pthread_key_create(keyptr, destructor);
    if (error != 0) {
        err_msg("pthread_key_create error", error);
    }
    return(error);
}

void * Pthread_getspecific(pthread_key_t key)
{
    return((void *)pthread_getspecific(key));
}

int Pthread_setspecific(pthread_key_t key, const void * value)
{
    int error = pthread_setspecific(key, value);
    if (error != 0) {
        err_msg("pthread_setspecific error", error);
    }
    return(error);
}

int Pthread_mutex_lock(pthread_mutex_t * mptr)
{
    int error = pthread_mutex_lock(mptr);
    if (error != 0) {
        err_msg("pthread_mutex_lock error", error);
    }
    return(error);
}

int Pthread_mutex_unlock(pthread_mutex_t * mptr)
{
    int error = pthread_mutex_unlock(mptr);
    if (error != 0) {
        err_msg("pthread_mutex_unlock error", error);
    }
    return(error);
}

int Pthread_cond_signal(pthread_cond_t * cptr)
{
    int error = pthread_cond_signal(cptr);
    if (error != 0) {
        err_msg("pthread_cond_signal error", error);
    }
    return(error);
}

int Pthread_cond_broadcast(pthread_cond_t * cptr)
{
    int error = pthread_cond_broadcast(cptr);
    if (error != 0) {
        err_msg("pthread_cond_broadcast error", error);
    }
    return(error);
}

int Pthread_cond_wait(pthread_cond_t * cptr, 
                      pthread_mutex_t * mptr)
{
    int error = pthread_cond_wait(cptr, mptr);
    if (error != 0) {
        err_msg("pthread_cond_wait error", error);
    }
    return(error);
}

int Pthread_cond_timedwait(pthread_cond_t * cptr, 
                           pthread_mutex_t * mptr, 
                           const struct timespec * abstime)
{
    int error = pthread_cond_timedwait(cptr, mptr, abstime);
    if (error != 0) {
        err_msg("pthread_cond_timedwait error", error);
    }
    return(error);
}

void * Malloc(size_t size)
{
    void * ptr = malloc(size);
    if (ptr == NULL) {
        err_msg("malloc error", errno);
    }
    return(ptr);
}

void * Calloc(size_t nobj, size_t size)
{
    void * ptr = calloc(nobj, size);
    if (ptr == NULL) {
        err_msg("calloc error", errno);
    }
    return(ptr);
}

int Socket(int family, int type, int protocol)
{
    int sockfd = socket(family, type, protocol);
    if (sockfd == -1) {
        err_msg("socket error", errno);
    }
    return(sockfd);
}

int Connect(int sockfd, const struct sockaddr * servaddr, socklen_t addrlen)
{
    int ret = connect(sockfd, servaddr, addrlen);
    if (ret == -1) {
        err_msg("connect error", errno);
    }
    return(ret);
}

int Bind(int sockfd, const struct sockaddr * myaddr, socklen_t addrlen)
{
    int ret = bind(sockfd, myaddr, addrlen);
    if (ret == -1) {
        err_msg("bind error", errno);
    }
    return(ret);
}

int Listen(int sockfd, int backlog)
{
    int ret = listen(sockfd, backlog);
    if (ret == -1) {
        err_msg("listen error", errno);
    }
    return(ret);
}

int Accept(int sockfd, struct sockaddr * cliaddr, socklen_t * addrlen)
{
    int ret = accept(sockfd, cliaddr, addrlen);
    if (ret == -1) {
        err_msg("accept error", errno);
    }
    return(ret);
}

pid_t Fork(void)
{
    int ret = fork();
    if (ret == -1) {
        err_msg("fork error", errno);
    }
    return(ret);
}

int Close(int sockfd)
{
    int ret = close(sockfd);
    if (ret == -1) {
        err_msg("close error", errno);
    }
    return(ret);
}

int Shutdown(int sockfd, int howto)
{
    int ret = shutdown(sockfd, howto);
    if (ret == -1) {
        err_msg("shutdown error", errno);
    }
    return(ret);
}

int Getsockname(int sockfd, struct sockaddr * localaddr, socklen_t * addrlen)
{
    int ret = getsockname(sockfd, localaddr, addrlen);
    if (ret == -1) {
        err_msg("getsockname error", errno);
    }
    return(ret);
}

int Getpeername(int sockfd, struct sockaddr * peeraddr, socklen_t * addrlen)
{
    int ret = getpeername(sockfd, peeraddr, addrlen);
    if (ret == -1) {
        err_msg("getpeername error", errno);
    }
    return(ret);
}


#endif

#include "warp.h"
#include "tcp_connect.h"

static int    sockfd;  /* global for both threads to access */
static FILE * fp;

void * 
copyto(void * arg)
{
    int   n;
    char  sendline[MAXLINE];

    while (fgets(sendline, MAXLINE, fp) != NULL) {
        n = strlen(sendline);
        if (writen(sockfd, sendline, n) != n) {
            err_msg("writen error", errno);
        }
    }
    if (ferror(fp)) {
        err_msg("fgets error", errno);
    }

    Shutdown(sockfd, SHUT_WR);  /* EOF on stdin, send FIN */

    return(NULL);
}

void 
str_cli(FILE * fp_arg, int sockfd_arg)
{
    int        n;
    char       recvline[MAXLINE];
    pthread_t  tid;

    sockfd = sockfd_arg;  /* copy arguments to externals */
    fp = fp_arg;

    Pthread_create(&tid, NULL, copyto, NULL);

    while ((n = readline(sockfd, recvline, MAXLINE)) > 0) {
        if (fputs(recvline, stdout) == EOF) {
            err_msg("fputs error", errno);
        }
    }
    if (n < 0) {
        err_msg("readline error", errno);
    }
}

int 
main(int argc, char ** argv)
{
    int  sockfd;

    if (argc != 3) {
        printf("usage: tcpcli <hostname> <service>\n");
        exit(1);
    }

    sockfd = tcp_connect(argv[1], argv[2]);

    str_cli(stdin, sockfd);  /* do it all */

    exit(0);
}
#include "warp.h"

void * 
doit(void *arg)  /* each thread executes this function */
{
    int  connfd;

    connfd = *((int *)arg);
    free(arg);

    Pthread_detach(Pthread_self());
    str_echo(connfd);  /* same function as before */
    close(connfd);  /* done with connected socket */
    return(NULL);
}

int 
main(int argc, char ** argv)
{
    int               listenfd;
    int             * iptr;
    pthread_t         tid;
    socklen_t         addrlen;
    socklen_t         len;
    struct sockaddr * cliaddr;

    if (argc == 2) {
        listenfd = tcp_listen(NULL, argv[1], &addrlen);
    }
    else if (argc == 3) {
        listenfd = tcp_listen(argv[1], argv[2], &addrlen);
    }
    else {
        printf("usage: tcpserv01 [ <host> ] <service or port>\n");
        exit(1);
    }

    cliaddr = Malloc(addrlen);

    for ( ; ; ) {
        len = addrlen;
        iptr = Malloc(sizeof(int));
        *iptr = Accept(listenfd, cliaddr, &len);
        Pthread_create(&tid, NULL, &doit, iptr);
    }
}

#include "warp.h"

static pthread_key_t   rl_key;
static pthread_once_t  rl_once = PTHREAD_ONCE_INIT;

void 
readline_destructor(void * ptr)
{
    free(ptr);
}

void 
readline_once(void)
{
    Pthread_key_create(&rl_key, readline_destructor);
}

typedef struct {
    int    rl_cnt;           /* initialize to 0 */
    char * rl_bufptr;        /* initialize to rl_buf */
    char   rl_buf[MAXLINE];
} Rline;

ssize_t 
my_read(Rline * tsd, int fd, char * ptr)
{
    if (tsd->rl_cnt <= 0) {
again:
        if ((tsd->rl_cnt = read(fd, tsd->rl_buf, MAXLINE)) < 0) {
            if (errno == EINTR) {
                goto again;
            }
            else {
                return(-1);
            }
        }
        else if (tsd->rl_cnt == 0) {
            return(0);
        }
        else {
            tsd->rl_bufptr = tsd->rl_buf;
        }
    }

    tsd->rl_cnt--;
    *ptr = *tsd->rl_bufptr++;
    return(1);
}

ssize_t 
readline(int fd, void * vptr, size_t maxlen)
{
    size_t   n;
    size_t   rc;
    char     c;
    char   * ptr;
    Rline  * tsd;

    Pthread_once(&rl_once, readline_once);
    if ((tsd = Pthread_getspecific(rl_key)) == NULL) {
        tsd = Calloc(1, sizeof(Rline));  /* init to 0 */
        Pthread_setspecific(rl_key, tsd);
    }

    ptr = vptr;
    for (n = 1; n < maxlen; n++) {
        if ((rc = my_read(tsd, fd, &c)) == 1) {
            *ptr++ = c;
            if (c == '\n') {
                break;
            }
        }
        else if (rc == 0) {
            *ptr = 0;
            return(n - 1);  /* EOF, n - 1 bytes read */
        }
        else {
            return(-1);  /* error, errno set by read() */
        }
    }

    *ptr = 0;
    return(n);
}

ssize_t 
Readline(int fd, void * ptr, size_t maxlen)
{
    ssize_t n = readline(fd, ptr, maxlen);
    if (n < 0) {
        err_msg("readline error", errno);
    }
    return(n);
}

#include "myio.h"
#include "warp.h"
#include "tcp_connect.h"

#define    MAXFILES    20
#define    SERV        "80"   /* port number or service name */

#define    F_CONNECTING    1    /* connect() in progress */
#define    F_READING       2    /* connect() complete; now reading */
#define    F_DONE          4    /* all done */
#define    F_JOINED        8    /* main has pthread_join'ed */

#define    GET_CMD        "GET %s HTTP/1.0\r\n\r\n"

#define    min(a, b)       ((a) < (b) ? (a) : (b))

struct file {
    char     * f_name;   /* filename */
    char     * f_host;   /* hostname or IP address */
    int        f_fd;     /* descriptor */
    int        f_flags;  /* F_xxx above */
    pthread_t  f_tid;    /* thread ID */
} file[MAXFILES];

int  nconn;
int  nfiles;
int  nlefttoconn;
int  nlefttoread;

int              ndone;  /* number of terminated threads */
pthread_mutex_t  ndone_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t   ndone_cond = PTHREAD_COND_INITIALIZER;

void 
home_page(const char * host, const char * fname)
{
    int   fd;
    int   n;
    char  line[MAXLINE];

    fd = tcp_connect(host, SERV);  /* blocking connect() */

    n = snprintf(line, sizeof(line), GET_CMD, fname);
    if (writen(fd, line, n) != n) {
        err_msg("writen error", errno);
    }

    for ( ; ; ) {
        if ((n = read(fd, line, MAXLINE)) < 0) {
            err_msg("read error", errno);
        }
        else if (n == 0) {
            break;  /* server closed connection */
        }
        printf("read %d bytes of home page\n", n);
        /* do whatever with data */
    }
    printf("end-of-file on home page\n");
    Close(fd);
}

void 
write_get_cmd(struct file * fptr)
{
    int   n;
    char  line[MAXLINE];

    n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);
    if (writen(fptr->f_fd, line, n) != n) {
        err_msg("writen error", errno);
    }
    printf("wrote %d bytes for %s\n", n, fptr->f_name);

    fptr->f_flags = F_READING;  /* clears F_CONNECTING */
}

void * 
do_get_read(void * vptr)
{
    int           fd;
    int           n;
    char          line[MAXLINE];
    struct file * fptr;

    fptr = (struct file *)vptr;

    fd = tcp_connect(fptr->f_host, SERV);
    fptr->f_fd = fd;
    printf("do_get_read for %s, fd %d, thread %d\n",
            fptr->f_name, fd, (int)fptr->f_tid);

    write_get_cmd(fptr);  /* write() the GET command */

    /* Read server's reply */
    for ( ; ; ) {
        if ((n = read(fd, line, MAXLINE)) < 0) {
            err_msg("read error", errno);
        }
        else if (n == 0) {
            break;  /* server closed connection */
        }
        printf("read %d bytes from %s\n", n, fptr->f_name);
    }
    printf("end-of-file on %s\n", fptr->f_name);
    Close(fd);
    fptr->f_flags = F_DONE;  /* clears F_READING */

    Pthread_mutex_lock(&ndone_mutex);
    ndone++;
    Pthread_cond_signal(&ndone_cond);
    Pthread_mutex_unlock(&ndone_mutex);

    return(fptr);  /* terminate thread */
}

int 
main(int argc, char ** argv)
{
    int           i;
    int           maxnconn;
    pthread_t     tid;
    struct file * fptr;

    if (argc < 5) {
        printf("usage: web <#conns> <IPaddr> <homepage> file1 ...\n");
        exit(1);
    }
    maxnconn = atoi(argv[1]);

    nfiles = min(argc - 4, MAXFILES);
    for (i = 0; i < nfiles; i++) {
        file[i].f_name = argv[i + 4];
        file[i].f_host = argv[2];
        file[i].f_flags = 0;
    }
    printf("nfiles = %d\n", nfiles);

    home_page(argv[2], argv[3]);

    nlefttoread = nlefttoconn = nfiles;
    nconn = 0;

    while (nlefttoread > 0) {
        while (nconn < maxnconn && nlefttoconn > 0) {
            /* find a file to read */
            for (i = 0 ; i < nfiles; i++) {
                if (file[i].f_flags == 0) {
                    break;
                }
            }
            if (i == nfiles) {
                printf("nlefttoconn = %d but nothing found\n", nlefttoconn);
                exit(1);
            }

            file[i].f_flags = F_CONNECTING;
            Pthread_create(&tid, NULL, &do_get_read, &file[i]);
            file[i].f_tid = tid;
            nconn++;
            nlefttoconn--;
        }

        /* Wait for thread to terminate */
        Pthread_mutex_lock(&ndone_mutex);
        while (ndone == 0) {
            Pthread_cond_wait(&ndone_cond, &ndone_mutex);
        }

        for (i = 0; i < nfiles; i++) {
            if (file[i].f_flags & F_DONE) {
                Pthread_join(file[i].f_tid, (void **) &fptr);

                if (&file[i] != fptr) {
                    printf("error: file[i] != fptr\n");
                    exit(1);
                }
                fptr->f_flags = F_JOINED;    /* clears F_DONE */
                ndone--;
                nconn--;
                nlefttoread--;
                printf("thread %d for %s done\n", 
                       (int)fptr->f_tid, fptr->f_name);
            }
        }

        Pthread_mutex_unlock(&ndone_mutex);
    }

    exit(0);
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值