第二十六章 线程:
#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);
}