zoukankan      html  css  js  c++  java
  • 线程(thread)

    线程(thread):
    现代操作系统引入进程概念,为了并发(行)任务

    1.进程之间的这种切换代价很高
    2.通信方式的代价也很大
    基本概念:

    1.线程是比进程更小的资源单位,它是进程中的一个执行路线(分支)
    2.线程同进程内其它线程共享地址空间(代码段、数据段、堆...)
    3.线程也称为轻量级进程
    线程特点:
    1.创建一个线程比创建一个进程开销要小的多

    2.线程间通信十分方便

    3.线程也是一个动态的概念

    4.在进程内创建多个线程,可以提高系统的并发处理能力

    5.每个进程至少有一个线程(主线程、main线程)

    6.进程是系统分配资源的最小单位,线程是任务高度的最小单位

    7.标准C中不包括线程,需要额外的库才能实现线程

    posix thread ->pthread


    ------------------
    Linux下线程相关API

    1.线程创建
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
    void *(*start_routine) (void *), void *arg);
    功能:用于创建一个新线程
    第一个参数:指针类型,用于存储新线程的ID(线程ID是用来唯一标识一个线程)
    第二个参数:指定新创建线程的属性(栈空间、优先级等),一般给NULL表示采用默认属性
    第三个参数:函数指针类型,新线程的执行处理函数
    第四个参数:指针类型,作为第三个参数实参
    返回值:成功返回0
    失败返回错误编码
    Compile and link with -pthread.
    编译链接时要带上pthread库

    man -k pthread 查看pthread库中的所有函数

    2.线程标识
    进程ID在整个系统中唯一的
    线程ID在所所属的进程环境有效
    pthread_t pthread_self(void);
    功能:获得调用线程的ID

    3.多线程之间的关系
    调用pthread_create创建出来的新线程,叫子线程,原来的线程叫主线程,创建成功后两个纯线程独立运行,执行顺序是由操作系统调度。

    在同一个进程间,主线程结束时,会导致其它所有子线程结束。(相互影响又相互独立)


    4.线程等待
    int pthread_join(pthread_t thread, void **retval);
    第一个参数:线程ID
    第二个参数:二级指针,用于获取线程的退出状态
    返回值:成功返回0,失败返回错误码。
    功能:一般此函数用于主线程中,等待thread指定的线程结束,如果调用成功,可以通过retval获取终止线程的返回值。
    如果等待的线程没有结束,此函数将引起调用者阻塞。


    5.线程的退出
    void pthread_exit(void *retval);
    功能:用于终止当前正在调用的线程,通过参数返回当前线程的退出状态
    可以使用同一进程中其它线程调用pthread_join函数来获取退出状态


    练习:
    创建一个子线程,在子线程中计算圆的面积,圆的半径通过参数传递,计算成功后把结果返回给主线程,并打印出来。


    4.线程的同步

    回顾:
    信号量集
    信号量工作方式:
    P操作 减1

    V操作 加1

    ftok()
    semget()
    semop()
    semctl()

    信号量与共享内存:
    read.c ->创建
    1.获取/创建信号量
    2.初始化信号量
    3.创建/获取共享内存
    4.映射到进程地址空间
    5.操作
    占用信号量 P操作
    read(quit退出)
    释放信号量 V操作

    6.删除信号量
    7.解除映射
    8.删除共享内存

    write.c ->使用
    1.创建/获取信号量
    2.创建/获取共享内存
    3.映射用户空间
    4.操作
    占用信号量 P操作
    write (quit退出)
    释放信号量 V操作

    5.解除映射

    struct message
    {
    char buf[256];
    int num ;
    };

    --------------------------------
    线程:
    线程创建
    pthread_t id;
    pthread_create(&id,NULL,线程执行函数,void*arg);

    线程终止
    pthread_exit(void*retval);

    线程等待
    void *retval;
    pthread_join(id,&retval);

    线程取消
    int pthread_cancel(pthread_t thread);
    在别的线程中去取消别一个线程
    被取消的线程可以设置自己的状态:
    被取消的线程接收到别一个线程的取消请求,是接受还是忽略这个请求
    如果接受,是立该进行终止,还是待某个函数的调用等
    int pthread_setcancelstate(int state, int *oldstate);
    第一个参数:设置最新状态
    PTHREAD_CANCEL_ENABLE 允许被取消(默认状态)
    PTHREAD_CANCEL_DISABLE 不允许被取消
    第二个参数:获取之前的取消状态,不需要获取则给NULL

    int pthread_setcanceltype(int type, int *oldtype);
    第一个参数:设置最新取消类型
    PTHREAD_CANCEL_DEFERRED 延迟取消(默认)
    PTHREAD_CANCEL_ASYNCHRONOUS 立即取消
    第二个参数:获取之前的取消类型,不需要获取则给NULL

    线程分离:
    int pthread_detach(pthread_t thread);
    功能:用于标记参数指定的线程为分离状态
    对于一个分离状态的线程来说,当该线程结束时,自动释放资源
    使用默认值新创建的线程是非分离状态,不该线程退出时,不会主动释放资源,必须要其它线程pthread_join


    ------------------
    线程同步问题:
    在同一个进程的多线程之间共享所在进程的地址空间,如果多个线程同时访问一个共享资源,可能会导致数据的混乱,为了解决该问题就需要线程之间的协调,而线程之间的协调和通信叫线程的同步问题
    gnum = 0;
    gnum++;

    lock
    从内存把数据读到寄存器
    在寄存器把数据加1
    完成再把数据写回内存
    unlock

    1.信号量
    1.定义信号量
    sem_t sem;
    2.初始化信号量
    int sem_init(sem_t *sem, int pshared, unsigned int value);
    sem_init(&sem,0,1);
    3.获取信号量 (信号量减1)
    int sem_wait(sem_t *sem);
    sem_wait(&sem);
    4.访问共享资源
    5.释放信号量
    int sem_post(sem_t *sem);
    sem_post(&sem);

    6.如果不再使用,则销毁信号量
    int sem_destroy(sem_t *sem);
    sem_destroy(&sem);

    练习:
    创建两个线程

    一个线程用来读文件
    把写入的数据读出来

    一个线程用来写文件
    往文件中写入5个hello world

    文件名从命令行传入


    2.互斥量(锁)
    3.条件变量


    /*************************************************************************
    > File Name: cancel.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Fri 12 Aug 2016 11:36:35 AM CST
    ************************************************************************/

    #include<stdio.h>
    #include<pthread.h>
    pthread_t id1,id2;
    void *thread1(void* arg)
    {
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
    printf("线程1正在运行! ");
    sleep(1);
    }
    printf("线程1被取消 ");
    return (void*)2;
    }

    void *thread2(void* arg)
    {
    printf("线程2在运行! ");
    sleep(5);
    printf("线程2请求取消线程1 ");
    pthread_cancel(id1);

    }

    int main()
    {

    pthread_create(&id1,NULL,thread1,NULL);

    pthread_create(&id2,NULL,thread2,NULL);
    void *retval;
    int r;
    r = pthread_join(id1,&retval);
    if(r != 0)
    {
    perror("join");
    }
    else
    {
    printf("pthread1 join ");
    }

    pthread_join(id2,NULL);

    printf("thread1 retval = %d ",(int )retval);
    }

    /*************************************************************************
    > File Name: detach.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Fri 12 Aug 2016 02:23:07 PM CST
    ************************************************************************/

    #include<stdio.h>
    #include<pthread.h>
    #include<string.h>
    void *thread(void*arg)
    {
    int i = 5;
    while(i--)
    {
    printf("this is thread run! ");
    sleep(1);
    }
    }

    int main()
    {
    pthread_t tid;
    pthread_create(&tid,NULL,thread,NULL);
    pthread_detach(tid);
    int res;
    res = pthread_join(tid,NULL);
    if(res != 0)
    {

    fprintf(stderr,"join:%s ",strerror(res));
    }

    return 0;

    }

    /*************************************************************************
    > File Name: pthread1.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Thu 11 Aug 2016 04:16:34 PM CST
    ************************************************************************/

    #include<stdio.h>
    #include<pthread.h>
    #include<stdlib.h>
    #include<string.h>
    void *newThread(void *arg)
    {
    printf("我就是那个新创建的线程 ");
    printf("子线程的ID :%lu,PID是%d ",pthread_self(),getpid());
    return (void*)123456;
    }

    int main()
    {
    pthread_t tid;
    pthread_t mid;
    int res;
    void *retval;
    res = pthread_create(&tid,NULL,newThread,NULL);
    if(res != 0)
    {
    fprintf(stderr,"pthread_cread:%s",strerror(res));
    exit(-1);
    }

    printf("主线程的ID:%lu,PID是%d ",pthread_self(),getpid());
    pthread_join(tid,&retval);
    printf("线程退出状态为:%d ",(int )(retval));


    }

    /*************************************************************************
    > File Name: sem_read.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Fri 12 Aug 2016 09:33:14 AM CST
    ************************************************************************/

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/sem.h>
    #include<string.h>
    struct sembuf buf;
    int sem_p(int semid)
    {
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = 0;
    int r = semop(semid,&buf,1);
    if(r == -1)
    {
    perror("sem_p");
    return -1;
    }
    return 0;
    }
    int sem_v(int semid)
    {
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = 0;
    int r = semop(semid,&buf,1);
    if(r == -1)
    {
    perror("sem_v");
    return -1;
    }
    return 0;
    }
    struct messge
    {
    int num;
    char msg[256];
    };
    int main()
    {
    //1.
    key_t key = ftok(".",100);
    if(key < 0)
    {
    perror("ftok");
    exit(-1);
    }
    int semid;
    semid = semget(key,1,0666 | IPC_CREAT);
    if(semid < 0)
    {
    perror("semget");
    exit(-1);
    }
    //2.
    semctl(semid,0,SETVAL,1);
    //3.
    int shmid;
    shmid= shmget(key,1024,0666 | IPC_CREAT);
    if(shmid < 0)
    {
    perror("shmget");
    exit(-1);
    }
    //4.
    void *shm_addr;
    shm_addr = (char*)shmat(shmid,NULL,0);
    if(shm_addr == (void*)-1)
    {
    perror("shmat");
    exit(-1);
    }
    struct messge *msgd;
    msgd = shm_addr;

    sleep(5);
    //5.
    char buf[256] = {0};
    while(1)
    {
    if(sem_p(semid))
    {
    exit(-1);
    }
    printf("进入读进程: ");
    // strcpy(buf,shm_addr);

    printf("消息编号是%d,读到的内容:%s ",msgd->num,msgd->msg);
    printf("离开读进程! ");
    if(sem_v(semid))
    {
    exit(-1);
    }
    if(strncmp(msgd->msg,"quit",4) == 0)
    {
    break;
    }
    //.
    }
    //6.
    if(semctl(semid,0,IPC_RMID) == -1)
    {
    perror("semctl_rmid");
    exit(-1);
    }
    //7.
    if(shmdt(shm_addr) == -1)
    {
    perror("shmdt");
    exit(-1);
    }
    //8.
    if(shmctl(shmid,IPC_RMID,NULL) == -1)
    {
    perror("shmctl");
    exit(-1);
    }


    return 0;
    }

    /*************************************************************************
    > File Name: sem_read.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Fri 12 Aug 2016 09:33:14 AM CST
    ************************************************************************/

    #include<stdio.h>
    #include<unistd.h>
    #include<stdlib.h>
    #include<sys/ipc.h>
    #include<sys/sem.h>
    #include<string.h>
    struct message
    {
    int num;
    char msg[256];

    };

    struct sembuf buf;
    int sem_p(int semid)
    {
    buf.sem_num = 0;
    buf.sem_op = -1;
    buf.sem_flg = 0;
    int r = semop(semid,&buf,1);
    if(r == -1)
    {
    perror("sem_p");
    return -1;
    }
    return 0;
    }
    int sem_v(int semid)
    {
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = 0;
    int r = semop(semid,&buf,1);
    if(r == -1)
    {
    perror("sem_v");
    return -1;
    }
    return 0;
    }

    int main()
    {
    //1.
    key_t key = ftok(".",100);
    if(key < 0)
    {
    perror("ftok");
    exit(-1);
    }
    int semid;
    semid = semget(key,1,0666 | IPC_CREAT);
    if(semid < 0)
    {
    perror("semget");
    exit(-1);
    }
    //2.
    // semctl(semid,0,SETVAL,1);//做为非创建者,不需要初始化,直接用就可
    //3.
    int shmid;
    shmid= shmget(key,1024,0666 | IPC_CREAT);
    if(shmid < 0)
    {
    perror("shmget");
    exit(-1);
    }
    //4.
    void *shm_addr;
    shm_addr = (char*)shmat(shmid,NULL,0);
    if(shm_addr == (void*)-1)
    {
    perror("shmat");
    exit(-1);
    }
    struct message *msgd = shm_addr;
    msgd->num = 0;
    //5.
    char buf[256] = {0};
    while(1)
    {
    if(sem_p(semid))
    {
    exit(-1);
    }
    printf("进入写进程: ");
    fgets(buf,sizeof(buf),stdin);
    msgd->num++;
    strcpy(msgd->msg,buf);
    printf("离开写进程! ");

    if(sem_v(semid))
    {
    exit(-1);
    }
    if(strncmp(buf,"quit",4) == 0)
    {
    break;
    }
    //.
    }
    //7.
    if(shmdt(shm_addr) == -1)
    {
    perror("shmdt");
    exit(-1);
    }

    return 0;
    }

    /*************************************************************************
    > File Name: test.c
    > Author: csgec
    > Mail: longer.zhou@gmail.com
    > Created Time: Fri 12 Aug 2016 02:30:31 PM CST
    ************************************************************************/

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

    #include <semaphore.h>


    sem_t sem;
    void *thread(void*arg)
    {
    sem_wait(&sem);
    int num = (int)arg;
    int i;
    for(i = 0; i < 5; i++)
    {
    printf("这是线程%d ",num);
    sleep(1);
    }
    sem_post(&sem);

    }
    int main()
    {
    sem_init(&sem,0,1);
    pthread_t tid1,tid2;
    printf("ni ma ");
    pthread_create(&tid1,NULL,thread,(void*)1);

    pthread_create(&tid2,NULL,thread,(void*)2);

    pthread_join(tid1,NULL);
    printf("ni er ju ");
    pthread_join(tid2,NULL);

    printf("ni da ye ");

    sem_destroy(&sem);

    return 0;
    }

  • 相关阅读:
    AdminLTE 3.0发布了
    .NET Core ORM 类库Petapoco中对分页Page添加Order By对查询的影响
    【译】ASP.NET Core在 .NET Core 3.1 Preview 1中的更新
    物品编码中心所说的包装指示符
    Entity Framework Core生成的存储过程在MySQL中需要进行处理及PMC中的常用命令
    Asp.Net Core Mvc Razor之RazorPage
    基于Asp.Net Core MVC和AdminLTE的响应式管理后台之侧边栏处理
    Qt的下载地址
    由于MicrosoftVisualStudio14.0DesignerShadowCache导致的一个异常问题
    Spring系列.事务管理原理简析
  • 原文地址:https://www.cnblogs.com/liudehao/p/5765234.html
Copyright © 2011-2022 走看看