zoukankan      html  css  js  c++  java
  • POSIX线程库复习

    创建一个新的线程

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
                              void *(*start_routine) (void *), void *arg);

    thread:返回线程ID

    attr:设置线程的属性,attr为NULL表示使用默认属性。

    start_toutine:是个函数地址,线程启动后要执行的函数

    arg:传给线程启动函数的参数。

    成功返回0,失败返回错误码;

     

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <pthread.h>
    #include <unistd.h>
    #include <sys/types.h>
    
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    
    void* therad_routine(void *arg)
    {
        int i;
        for (i = 0; i < 20; ++i)
        {
            /* code */
            printf("B");
            fflush(stdout);
        }
        return 0;
    }
    
    
    int main(int argc, const char *argv[])
    {
        pthread_t tid;
        int ret;
        ret = pthread_create(&tid, NULL, therad_routine, NULL);
        if(ret != 0)
        {
            fprintf(stderr, "pthread_create:%s
    ", strerror(ret));
            exit(EXIT_FAILURE);
        }
        int i;
        for (i = 0; i < 20; ++i)
        {
            /* code */
            printf("A");
            fflush(stdout);
            usleep(20);
        }
        sleep(1);
        return 0;
    }
    当线程创建失败时, 错误信息会返回到errno中。

    pthread同样也提供了线程内的而errno变量,一支持其他使用errno的代码,

    对于pthreads函数的错误,简易通过返回值判定,因为赌气返回值要比赌气线程内的errno变量的开销更小。

    打印结果

    ABABABABABAB

    可以看得出单核的情况下,主线程和线程之间是共享CPU时间片的。

    它们是交替进行的。

    ret = pthread_join(tid, NULL);
        if(ret != 0)
        {
            fprintf(stderr, "pthread_join:%s
    ", strerror(ret));
            exit(EXIT_FAILURE);
        }

    主线程利用pthread_join来回收线程资源。

    相对于多进程下僵尸进程的概念,多线程中也会产生僵尸线程。

    所以我们可以使用pthread_detach来分离一个线程,这样便不会产生僵尸线程。

    下面利用线程函数实现一个简单的回射服务器练习一下

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    
    void* thread_routine(void* arg)
    {
        pthread_detach(pthread_self());
        int conn = (int)arg;
        echo_sev(conn);
        printf("exiting thread ....
    ");
        return 0;
    }
    
    
    int main(int argc, const char *argv[])
    {
        int listen = socket(PF_INET, SOCK_STREAM, 0);
        if(socket < 0 )
            ERR_EXIT("socket");
        struct sockaddr_in servraddr;
        servaddr.sin_family = AF_INET;
        servaddr.sin_port = htons(5188);
        servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    
        int on = 1;
        //设置端口复用
        if(setsocketopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &ON, sizeof(on)) <0)
            ERR_EXIT("setsocketopt");
        if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) <0)
            ERR_EXIT("bind");
    
        if(listen(listenfd, SOMAXCONN)<0)
            ERR_EXIT("listen");
        struct sockaddr_in peeraddr;
        socklen_t peerlen;
        int conn;
        while(1)
        {
            conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
            if(conn < 0)
                ERR_EXIT("accept");
    
            printf("ip = %s, port = %d
    ", inet_ntoa(peeraddr.sin_addr, ntohs(peeraddr.sin_port)));
            pthread_t tid;
            int ret;
            ret = pthread_create(&tid, NULL, thread_routine, (void*)conn);
            if(ret != 0)
            {
                fprintf(stderr, "pthread_create:%s
    ", strerrno(ret));
                exit(EXIT_FAILURE);
            }
        }
    
        
        return 0;
    }

    注意点就是,要将创建的线程进行detrach,来避免僵尸线程的产生。

    二。线程属性

    通过设置pthread_create的第二个参数来来达到我们的但的目的。

    分离属性的获取与设置

    int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);

    这个函数有两个参数,

    PTHREAD_CREATE_DETACHED:

              所以创建的线程都会是分离的。

    PTHREAD_CREATE_JOINABLE:

    所有新创建的线程都是不分离的。

    实例代码如下

    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    
    int main(int argc, const char *argv[])
    {
        //先定义个线程属性变量并初始化
        pthread_attr_t attr;
        pthread_attr_init(&attr);
    // 完成上面两部之后,attr中会保存各种线程的默认属性
        int state;
        pthread_attr_getdetachstate(&attr, &state);
        if(state == PTHREAD_CREATE_JOINABLE)
            printf("datechstate:PTHREAD_CRRATE_JOINABLE
    ");
        else if(state == PTHREAD_CREATE_DETACHED)
            printf("datechstate:PTHREAD_CRRATE_DETACHED
    ");
    
        size_t size;
        pthread_attr_getstacksize(&attr, &size);
        printf("stacksize:%d
    ", size);
    
        pthread_attr_getguardsize(&attr, &size);
        printf("guardsize:%d
    ", size);
        return 0;
    }

    可以通过上述的几个函数来获取线程的属性。

    线程除了属性,还有128个特定的指针可以用于保存TSD即线程特有数据

    需要手动自己create,可以指向任意的数据类型

    #include <pthread.h>
    #include <unistd.h>
    #include <errno.h>
    #include <sys/types.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define ERR_EXIT(m) 
        do { 
            perror(m);
            exit(EXIT_FAILURE);
        }while(0)
    typedef struct tsd
    {
        pthreead_t tid;
        char *str;
    }tsd_t;
    
    
    pthread_key_t key_tsd;
    void destroy_routine(void *value)
    {
        printf("销毁。。。特定数据
    ");
        free(value);
    }
    
    void thread_routine(void *value)
    {
        tsd_t *value = (tsd_t*)malloc(sizeof(tsd_t));
        value->tid = pthread_self();
        value->str = (char*)arg;
    
        pthread_setspecific(key_tsd, value);
        printf("%ssetspecific%p
    ", (char*)arg, value);
        value = pthread_getspecific(key_tsd);
        printf("tid=0x%x, str=%s
    ", value->tid, value->str);
        sleep(2);
    
    
        return 0;
    }
    int main(int argc, const char *argv[])
    {
    
        pthread_key_create(tsd, destroy_routine);
    
        pthread_t tid1;
        pthread_t tid2;
        pthread_create(&tid1, NULL, thread_routine, "thread1");
        pthread_create(&tid2, NULL, thread_routine, "thread2");
    
        pthread_join(&tid1, NULL);
        pthread_join(&tid2, NULL);
    
    
        pthread_key_delete(dkey_tsd);
        return 0;
    }

    解析:

    create函数会寻找一个数据空位。

    pthread_key_create(tsd, destroy_routine);

    线程退出后会自动调用destroy_routine指向的函数去销毁该TSD。

    pthread_setspecific(key_tsd, value);

    这个函数时将要保存的信息保存到放入我们申请的那个TSD中。

        value = pthread_getspecific(key_tsd);

    这个函数可以从TSD中获取到之前保存的数据。

  • 相关阅读:
    【转载】网站服务器运维记实:阿里云1核2G突发性能t5服务器突然变得卡顿
    【转载】C#中自定义Sort的排序规则IComparable接口
    【转载】C#将图片转换为二进制流调用
    【转载】ASP.NET MVC重写URL制作伪静态网页,URL地址以.html结尾
    Java通过反射机制修改类中的私有属性的值
    Android -- 分享功能和打开指定程序
    Java存储密码用字符数组
    java笔试题(3)
    Java中的String与常量池
    Android -- 距离感应器控制屏幕灭屏白屏
  • 原文地址:https://www.cnblogs.com/DLzhang/p/4337540.html
Copyright © 2011-2022 走看看