第14章 线程机制:并发函数的使用

多线程
●相关函数
1.pthread_create
在这里插入图片描述
在这里插入图片描述
独立线程不需要释放掉,执行完自动结束
在这里插入图片描述
pthread_create只能接受一个参数,当要传入多个参数时,可以用结构体来传参

2.pthread_join在这里插入图片描述
如果忘记使用pthread_join来收回线程,线程占用的资源就无法回收,类似于用malloc没有free

3.pthread_mutex_lock
用来避免访问冲突,在某一时刻只有唯一的线程可以对变量进行访问。
在这里插入图片描述
4.pthread_mutex_unlock
在这里插入图片描述
5.pthread_cond_wait
在这里插入图片描述
6.pthread_cond_signal
在这里插入图片描述
●线程间通信实例:同时统计两个文件的字数,先统计完的显示,两个都统计完就结束程序
 使用了编程设备的三项:容器、旗帜和锁。一个变量保存数据,一个条件对象和一个互斥量。
 原线程启动了两个计数线程然后开始等待结果的到来。当一个线程完成计数后,线程通过把指针存入邮箱变量的方式来传递结果。首先线程对邮箱加锁,然后检查邮箱,如果邮箱非空即主线程还未取出,线程就把锁打开等待取出后信号的到来,之后线程再一次锁住邮箱,把结果放入邮箱,然后发出信号并解锁。

#include  <stdio.h>
#include  <stdlib.h>
#include  <pthread.h>
#include  <ctype.h>

struct arg_set {    //要传递两个参数给线程,使用结构体传参
		char *fname;
		int  count;
};

struct arg_set  *mailbox = NULL;    //邮箱
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;   //互斥锁
pthread_cond_t  flag = PTHREAD_COND_INITIALIZER;    //条件变量

void *count_words(void *);
int main(int argc, char *argv[])
{
	pthread_t t1, t2;
	struct arg_set args1, args2;	
	int reports_in = 0;     //主线程收到的结果数量
	int	total_words = 0;

	if ( argc != 3 ){
		printf("usage: %s file1 file2\n", argv[0]);
		exit(1);
	}

	args1.fname = argv[1];
	args1.count = 0;
	pthread_create(&t1, NULL, count_words, (void *) &args1);

	args2.fname = argv[2];
	args2.count = 0;
	pthread_create(&t2, NULL, count_words, (void *) &args2);

	pthread_mutex_lock(&lock);  //先将锁锁住,方便调用cond_wait
	while( reports_in < 2 ){
		printf("MAIN: waiting for flag to go up\n");
        /*函数打开锁,并阻塞当前线程等待flag变化*/
		pthread_cond_wait(&flag, &lock);    
        /*flag改变,主线程从邮箱取数据*/
        printf("MAIN: Wow! flag was raised, I have the lock\n");
		printf("%7d: %s\n", mailbox->count, mailbox->fname);
		total_words += mailbox->count;
		if ( mailbox == &args1) 
			pthread_join(t1,NULL);
		if ( mailbox == &args2) 
			pthread_join(t2,NULL);
		mailbox = NULL;
        /*改变flag,告诉其它线程已经取完了*/
		pthread_cond_signal(&flag);	
		reports_in++;
	}
	pthread_mutex_unlock(&lock);
	
	printf("%7d: total words\n", total_words);
}
void *count_words(void *a)
{
	struct arg_set *args = a;//将void*型变量转变回去
	FILE *fp;
	int  c, prevc = '\0';
	
	if ( (fp = fopen(args->fname, "r")) != NULL ){
		while( ( c = getc(fp)) != EOF ){
            /*当前不为字符数字,前一个是字符数字,count就增1*/
			if ( !isalnum(c) && isalnum(prevc) )
				args->count++;
			prevc = c;
		}
		fclose(fp);
	} else 
		perror(args->fname);
	printf("COUNT: waiting to get lock\n");//统计完,准备关闭锁
	pthread_mutex_lock(&lock);//关闭锁
	printf("COUNT: have lock, storing data\n");
    /*主线程还未从邮箱取出上一个报告,阻塞直到主线程取出*/
	if ( mailbox != NULL ){
		printf("COUNT: oops..mailbox not empty. wait for signal\n");
		pthread_cond_wait(&flag,&lock);
	}
	mailbox = args;			
	printf("COUNT: raising flag\n");
	pthread_cond_signal(&flag);	//发//函数打开锁,并阻塞当前线程等待flag变化
送信号,告诉主线程来取
	printf("COUNT: unlocking box\n");
	pthread_mutex_unlock(&lock);//关闭锁
	return NULL;
}

在这里插入图片描述

●多线程web服务器
主循环

    while (1) {
        fd = accept(sock, NULL, NULL);
        server_requests++;
        fdpttr = malloc(sizeof(int));
        *fdptr = fd;
        pthread_create(&worker, &attr, handle_call, fdptr);//将fd作为参数传入
    }

/* twebserv.c - a threaded minimal web server (version 0.2)
 * usage : tws portnumber
 * features : supports the GET command only
 *          runs in the current directory
 *          creates a thread to handle each request
 *          supports a special status URL to report internal state
 * building : cc twebserv.c socklib.c -lpthread -o twebserv
 */

 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <string.h>

 #include <pthread.h>
 #include <stdlib.h>
 #include <unistd.h>

 #include <dirent.h>
 #include <time.h>

 /* server facts here */

 time_t     server_started;
 int        server_bytes_sent;
 int        server_requests;

 main(int ac, char *av[])
 {
    int sock, fd;
    int *fdptr;
    pthread_t worker;
    pthread_attr attr;

    void *handle_call(void *);

    if (ac == 1) {
        fprintf(stderr, "usage: tws portnum\n");
        exit(1);
    }
    sock = make_server_socket(atoi(av[1]));
    if (sock == -1) { perror("making socket"); exit(2); }

    setup(&attr);

    /* main loop here: take call, handle call in new thread */

    while (1) {
        fd = accept(sock, NULL, NULL);
        server_requests++;
        fdpttr = malloc(sizeof(int));
        *fdptr = fd;
        pthread_create(&worker, &attr, handle_call, fdptr);
    }
 }

 /*
  * initialize the status variables and
  * set the thread attribute to detached
  */
 setup(pthread_attr_t *attrp)
 {
    pthread_attr_init(attrp);
    pthread_attr_setdetachstate(attrp, PTHREAD_CREATE_DETACHED);

    time(&server_started);
    server_requests = 0;
    server_bytes_sent = 0;
 }

 void *handle_call(void *fdptr)
 {
    FILE *fpin;
    char request[BUFSIZ];
    int fd;

    fd = *(int *)fdptr;
    free(fdptr);                    /* get fd from arg */

    fpin = fdopen(fd, "r");         /* buffer input */
    fgets(request, BUFSIZ, fpin);   /* read client request */
    printf("got a call on %d: request = %s", fd, request);
    skip_rest_of_header(fpin);

    process_rq(request, fd);        /* process client rq */

    fclose(fpin);
 }

 /*------------------------------------------------------------------------------*
    skip_rest_of_header(FILE *)
    skip over all request info until a CRNL is seen
    -----------------------------------------------------------------------------*/
 skip_rest_of_header(FILE *fp)
 {
    char buf[BUFSIZ] = [];
    while (fgets(buf, BUFSIZ, fp) != NULL && strcmp(buf, "\r\n,") != 0)
        ;
 }

 /*------------------------------------------------------------------------------*
    process_rq(char *rq, int fd)
    do what the request asks for and write reply to fd
    handles request in a new process
    rq is HTTP command: GEt /foo/bar.html HTTP/1.0
    -----------------------------------------------------------------------------*/
 process_rq(char *rq, int fd)
 {
    char cmd[BUFSIZ], arg[BUFSIZ];

    if (sscanf(rq, "%s%s", cmd, arg) != 2)
        return;
    sanitize(arg);
    printf("sanitized version is %s\n", arg);

    if (strcmp(cmd, "GET") != 0)
        not_implemented();
    else if (built_in(arg, fd))
        ;
    else if (not_exist(arg))
        do_404(arg, fd);
    else if (isadir(arg))
        do_ls(arg, fd);
    else
        do_cat(arg, fd);
 }

 /*
  * make sure all paths are below the current directory
  */
 sanitize(char *str)
 {
    char *src, *dest;

    src = dest = str;

    while (*src) {
        if (strcmp(src, "/../", 4) == 0)
            src += 3;
        else if (srncmp(src, "//", 2) == 0)
            src++;
        else
            *dest++ = *src++;
    }
    *dest = '\0';
    if (*str == '/')
        strcpy(str, str + 1);

    if (str[0] == '\0' || strcmp(str, "./") == 0 || strcmp(str, "./..") == 0)
        strcpy(str, ".");
 }

 /* handle built - in URLs here. Only one so far is "status" */
 built_in(char *arg, int fd)
 {
    FILE *fp;

    if (strcmp(arg, "status") != 0)
        return 0;
    http_reply(fd, &fp, 200, "OK", "text/plain", NULL);

    fprintf(fp, "Server started: %s", ctime(&server_started));
    fprintf(fp, "Total requests: %d\n", server_requests);
    fprintf(fp, "Bytes sent out: %d\n", server_bytes_sent);
    fclose(fp);
    return 1;
 }

 http_reply(int fd, FILE **fpp, int code, char *msg, char *type, char *content)
 {
    FILE *fp = fdopen(fd, "w");
    int bytes = 0;

    if (fp != NULL) {
        bytes = fprintf(fp, "HTTP/1.0 %d %s\r\n", code, msg);
        bytes != fprintf(fp, "Content-type: %s\r\n\r\n", type);
        if (content)
            bytes += fprintf(fp, "%s\r\n", content);
    }
    fflush(fp);
    if (fpp)
        *fpp = fp;
    else
        fclose(fp);
    return bytes;
 }

/*------------------------------------------------------------------------------*
    simple functions first:
        not_implemented(fd)     unimplemented HTTP command
        and do_404(item, fd)    no such object
   -----------------------------------------------------------------------------*/
not_implemented(int fd)
{
    http_reply(fd, NULL, 501, "Not not_implemented", "text/plain", "That command is not not_implemented");
}

do_404(char *item, int fd)
{
    http_reply(fd, NULL, 404, "Not Found", "text/plain", "The item you seek is not here");
}

 /*------------------------------------------------------------------------------*
    the directory listing section
    isadir() uses stat, not_exist() uses stat
    -----------------------------------------------------------------------------*/

 isadir(char *f)
 {
    struct stat info;
    return (stat(f, &info) != -1 &7 S_ISDIR(info.st_mode));
 }

 not_exist(char *f)
 {
    struct stat info;
    return (stat(f, info) != -1);
 }

 do_ls(char *dir, int fd)
 {
    DIR *dirptr;
    struct dirent *direntp;
    FILE *fp;
    int bytes = 0;

    bytes = http_reply(fd, &fp, 200, "OK", "text/plian", NULL);
    bytes += fprintf(fp, "Listing of Directory %s\n", dir);

    if ((dirptr = opendir(dir)) != NULL) {
        while (direntp = readdir(dirptr)) {
            bytes += fprintf(fp, "%s\n", direntp->d_name);
        }
        closedir(dirptr);
    }
    fclose(fp);
    server_bytes_sent += bytes;
 }

 /*------------------------------------------------------------------------------*
    functions to cat files here.
    file_type(filename) returns the 'extension': cat uses it
    -----------------------------------------------------------------------------*/

 char *file_type(char *f)
 {
    char *cp;
    if ((cp = strrchr(f, '.')) != NULL)
        return cp + 1;
    return " -";
 }

 /* do_cat(filename, fd): sends header then the contents */

 do_cat(char *f, int fd)
 {
    char *extension = file_type(f);
    char *type = "text/plain";
    FILE *fpsock, *fpfile;
    int c;
    int bytes = 0;

    if (strcmp(extension, "html") == 0)
        type = "text/html";
    else if (strcmp(extension, "gif") == 0)
        type = "image/gif";
    else if (strcmp(extension, "jpg") == 0)
        type = "image/jpeg";
    else if (strcmp(extension, "jpeg") == 0)
        type = "image/jpeg";

    fpsock = fdopen(fd, "w");
    fpfile = fopen(f, "r");
    if (fpsock != NULL && fpfile != NULL)
    {
        bytes = http_reply(fd, &fpsock, 200, "OK", type, NULL);
        while ((c = getc(fpfile)) != EOF) {
            putc(c, fpsock);
            bytes++;
        }
        fclose(fpfile);
        fclose(fpsock);
    }
    server_bytes_sent += bytes;
 }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值