zoukankan      html  css  js  c++  java
  • TCP/IP 网络编程(六)


    流程模型:

    线程模型:

    线程的创建和运行流程

    #include <pthread.h>
    
    int pthread_create(pthread_t * restrict thread, const pthread_attr_t * restrict attr,
    void * (* start_routine)(void *), void * restrict arg); // 成功返回0, 失败返回其它值
    
    ~ thread: 保存新创建线程ID的变量地址值
    ~ attr: 用于传递线程属性的參数。NULL 表示默认
    ~ start_toutine: 线程单独的运行函数地址
    ~ arg: 第三个參数函数的參数信息变量地址值

    线程使用演示样例代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    void *thread_main(void *arg);
    
    int main(int argc, char *argv[])
    {
        pthread_t t_id;
        int thread_param = 5;
    
        if(pthread_create(&t_id, NULL, thread_main, (void *)&thread_param) != 0)
        {
            puts("pthread_creat() error");
            return -1;
        }
    
    
        sleep(10);
        puts("free maoolc and end of main");
        return 0;
    }
    void *thread_main(void *arg)
    {
        int i;
        int cnt = *((int *)arg);
        char * msg = (char *)malloc(sizeof(char) * 50);
        strcpy(msg, "Hello, I'am thread ~ 
    ");
        for(i=0; i<16; i++)
        {
            sleep(1);
            puts("running thread");
        }
        return (void *)msg;
    }

    运行流程例如以下:

    进程终止也会捎带线程结束。

    上述实例要求:线程相关程序中必须适当调用sleep函数。非常明显。这样的须要预測和安排运行流是不安全的。

    #include <pthread.h>
    
    int pthread_join(pthread_t thread, void ** status); // 成功返回0。 失败返回其它值
    
    ~ thread: 指定线程终止后才会从该函数返回
    ~ status: 保存线程函数返回值的指针变量地址值

    简言之。调用该函数的进程将进入等待状态。知道第一个參数指定的线程终止为止。

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    void *thread_main(void *arg);
    
    int main(int argc, char *argv[])
    {
        pthread_t t_id;
        int thread_param = 5;
        void * thr_ret;
    
        if(pthread_create(&t_id, NULL, thread_main, (void *)&thread_param) != 0)
        {
            puts("pthread_creat() error");
            return -1;
        }
    
        if(pthread_join(t_id, &thr_ret) != 0)
        {
            puts("pthread_join() error");
            return -1;
        }
    
        printf("Thread return message : %s 
    ", (char *)thr_ret);
        free(thr_ret);
        puts("free maoolc and end of main");
        return 0;
    }
    void *thread_main(void *arg)
    {
        int i;
        int cnt = *((int *)arg);
        char * msg = (char *)malloc(sizeof(char) * 50);
        strcpy(msg, "Hello, I'am thread ~ 
    ");
        for(i=0; i<16; i++)
        {
            sleep(1);
            puts("running thread");
        }
        return (void *)msg;
    }

    运行模型例如以下:

    线程存在的问题和临界区

    临界区:函数内同一时候运行多个线程时引起问题的多条语句构成的代码块,也就是对共享资源訪问并改动的代码。

    同步:

    • 同一时候訪问同一内存空间
    • 须要指定訪问同一内存空间的线程的运行顺序

    相互排斥量

    相互排斥量的创建及销毁函数:

    #include <pthread.h>
    
    int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    
    ~ mutex: 相互排斥量的地址值
    ~ attr: 要创建的相互排斥量属性,默认NULL

    对相互排斥量的锁定和释放:

    #include <pthread.h>
    
    int pthread_mutex_lock(pthread_mutex_t * mutex);
    int pthread_mutex_lock(pthread_mutex_t * mutex); // 成功返回0

    演示样例代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #define NUM_THREAD 100
    void * thread_inc(void *arg);
    void * thread_des(void *arg);
    
    long long num;
    pthread_mutex_t mutex;
    
    int main(int argc, char *argv[])
    {
        pthread_t thread_id[NUM_THREAD];
        int i;
    
        pthread_mutex_init(&mutex, NULL);
    
        for(i=0; i<NUM_THREAD; i++)
        {
            if(i%2)
                pthread_create(&(thread_id[i]), NULL, thread_inc, NULL);
            else
                pthread_create(&(thread_id[i]), NULL, thread_des, NULL);
        }
    
        for(i=0; i<NUM_THREAD; i++)
            pthread_join(thread_id[i], NULL);
    
        printf("result: %lld 
    ", num);
        pthread_mutex_destroy(&mutex);
        return 0;
    }
    void * thread_inc(void *arg)
    {
        int i;
        pthread_mutex_lock(&mutex); // 临界区划分范围较大
        for(i=0; i<50000000; i++)
            num += 1;
        pthread_mutex_unlock(&mutex); // 最大限度降低 lock、unlock 的调用
        printf("Done ");
        return NULL;
    }
    
    void * thread_des(void *arg)
    {
        int i;
        pthread_mutex_lock(&mutex);
        for(i=0; i<50000000; i++)
        {
            num -= 1;
        }
        pthread_mutex_unlock(&mutex);
        puts("Done des");
        return NULL;
    }

    结果是0.

    信号量

    信号量的创建和销毁:

    #include <semaphore.h>
    
    int sem_init(sem_t * sem, int pshared, unsigned int value);
    int sem_destroy(sem_t * sem); // 成功返回0
    
    ~ sem: 信号量的变量地址值
    ~ pshared: 创建可有多个进程共享的信号量,0代表在同一进程中使用
    ~ value: 信号量初始值

    对信号量的操作:

    int sem_post(sem_t * sem);
    int sem_wait(sem_t * sem); // 成功返回0

    演示样例代码:

    #include <stdlib.h>
    #include <stdio.h>
    #include <pthread.h>
    #include <semaphore.h>
    
    void * read(void * arg);
    void * accu(void *arg);
    static sem_t sem_one;
    static sem_t sem_two; // 两个信号量
    static int num;
    
    int main(int argc, char *atgv[])
    {
        pthread_t id_t1, id_t2; //两个线程
        sem_init(&sem_one, 0, 0); //信号量初始化为0
        sem_init(&sem_two, 0, 1);
    
        pthread_create(&id_t1, NULL, read, NULL);
        pthread_create(&id_t2, NULL, accu, NULL); // 创建线程
    
        pthread_join(id_t1, NULL);
        pthread_join(id_t2, NULL); // 等待线程结束
    
        sem_destroy(&sem_one);
        sem_destroy(&sem_two); //销毁信号量
    
        return 0;
    }
    void * read(void * arg)
    {
        int i;
        for(i=0; i<5; i++)
        {
            fputs("Input num : ", stdout);
            sem_wait(&sem_two); // 对信号量运行 V 操作
            scanf("%d", &num);
            sem_post(&sem_one); // 对信号量运行 P 操作
        }
        return NULL;
    }
    
    void * accu(void * arg)
    {
        int sum=0, i;
        for(i=0; i<5; i++)
        {
            sem_wait(&sem_one);
            sum += num;
            sem_post(&sem_two);
        }
        printf("Resule : %d 
    ", sum);
        return NULL;
    }

    线程的销毁和多线程server的实现

    • 调用pthread_join函数,不仅会等待线程结束还会引导线程销毁。线程终止前,调用该函数的进程将堵塞
    • 调用pthread_detach函数, 不会引起线程终止或者进入堵塞状态
    #include <pthread.h>
    
    int pthread_detach(pthread_t pthread); // 成功返回0

    多线程server端实现代码

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/socket.h>
    #include <string.h>
    #include <pthread.h>
    #include <arpa/inet.h>
    #include <unistd.h>
    
    #define BUF_SIZE 100
    #define MAX_CLNT 256
    
    void * handle_clnt(void *arg);
    void send_msg(char *msg, int len);
    void error_handling(char *msg);
    
    int clnt_cnt = 0;
    int clnt_socks[MAX_CLNT];
    pthread_mutex_t mutx;
    
    int main(int argc, char *argv[])
    {
        int serv_sock, clnt_sock;
        struct sockaddr_in serv_adr, clnt_adr;
        int clnt_adr_sz;
        pthread_t t_id;;
    
        if(argc != 2)
        {
            printf("Usage : %s <port> 
    ", argv[0]);
            exit(1);
        }
    
        pthread_mutex_init(&mutx, NULL); // 初始化相互排斥信号量
        serv_sock = socket(PF_INET, SOCK_STREAM, 0);  // 创建 socket 套接字
    
        memset(&serv_adr, 0, sizeof(serv_adr)); // 将server端套接字地址信息结构体初始化为全 0
        serv_adr.sin_family = AF_INET;
        serv_adr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_adr.sin_port = htons(atoi(argv[1]));
    
        if(bind(serv_sock,(struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
            error_handling("bind() error");
        if(listen(serv_sock, 5) == -1)
            error_handling("listen() error");
    
        while(1)
        {
            clnt_adr_sz = sizeof(clnt_adr);
            clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
            if(clnt_sock == -1)
                error_handling("accept() error");
    
            pthread_mutex_lock(&mutx); // 对相互排斥量加锁訪问
            clnt_socks[clnt_cnt++] = clnt_sock;
            pthread_mutex_unlock(&mutx);
    
            pthread_create(&t_id, NULL, handle_clnt, (void *)&clnt_sock);
            pthread_detach(t_id); //线程销毁方式
            printf("Connected client IP : %s 
    ", inet_ntoa(clnt_adr.sin_addr));
        }
        close(serv_sock);
        return 0;
    }
    
    void * handle_clnt(void * arg)
    {
        int clnt_sock = *((int*)arg);
        int str_len = 0;
        int i;
        char msg[BUF_SIZE];
    
        while((str_len = read(clnt_sock, msg, sizeof(msg))) != 0)
            send_msg(msg, str_len);
    
        // 运行到这里的时候就说明客户端请求断开连接
        pthread_mutex_lock(&mutx);
    
        // remove disconnected client
        // 在 clnt_socks 数组中保存全部的客户端套接字,移除一个之后
        // 要将该套接字后面的前移一位,因此这不是个合适的数据结构
    
        for(i=0; i<clnt_cnt; i++)
        {
            if(clnt_sock == clnt_socks[i])
            {
                while(i++ < clnt_cnt-1)
                    clnt_socks[i] = clnt_socks[i+1];
                break;
            }
        }
        clnt_cnt--;
        pthread_mutex_unlock(&mutx);
        close(clnt_sock);
        return NULL;
    }
    
    void send_msg(char *msg, int len) // send to all
    {
        int i;
        pthread_mutex_lock(&mutx);
        for(i=0; i<clnt_cnt; i++)
            write(clnt_socks[i], msg, len);
        pthread_mutex_unlock(&mutx);
    }
    
    void error_handling(char * msg)
    {
        fputs(msg, stderr);
        fputc('
    ', stderr);
        exit(1);
    }

    版权声明:本文博客原创文章。博客,未经同意,不得转载。

  • 相关阅读:
    Android 开发 深入理解Handler、Looper、Messagequeue 转载
    Android 开发 Handler的基本使用
    Java 学习 注解
    Android 开发 AlarmManager 定时器
    Android 开发 框架系列 百度语音合成
    Android 开发 框架系列 Google的ORM框架 Room
    Android 开发 VectorDrawable 矢量图 (三)矢量图动画
    Android 开发 VectorDrawable 矢量图 (二)了解矢量图属性与绘制
    Android 开发 VectorDrawable 矢量图 (一)了解Android矢量图与获取矢量图
    Android 开发 知晓各种id信息 获取线程ID、activityID、内核ID
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4660425.html
Copyright © 2011-2022 走看看