• Linux线程01


    学习任务

    线程的创建和取消
    线程的参数传递
    线程资源的回收,让线程有计划的退出

    进程和线程的区别

    1. 进程优点:可以在一个进程内是实现并发。
    2. 开销小创建线程比创建进程要快。
    3. 进程有pcb,有独立地址空间,线程本质还是进程, 线程有pcn没有独立地址空间
    4. 多进程,子进程挂了不影响其他进程。 多线程,一个子线程挂了,整个进程玩完犊子。

    线程的创建和终止

    创建,等待线程退出,查看线程

    创建线程
    int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
    等待线程退出 pthread_join(id,退出返回值);
    查看线程 ps- Lf 线程编号
    

    代码如下:

    #include <pthread.h>
    
    void* arg_main1(void* arg) {
        int cnt = *((int*)arg);
        for(int i = 0;i < cnt; i++) {
            
            printf("thread 1 sleep %d\n",i);
        }
    }
    void* arg_main2(void* arg) {
        int cnt = *((int*)arg);
        for(int i = 0;i < cnt; i++) {
            printf("thread2 sleep %d\n",i);
        }
    }
    int main()
    {
        pthread_t pid1,pid2;
        int arg = 4;
        if( pthread_create(&pid1,NULL,&arg_main1,(void*)&arg) != 0) {
            perror("pthread_create2 failed \n");
            return -1;
        }
        if( pthread_create(&pid2,NULL,&arg_main2,(void*)&arg) != 0) {
            perror("pthread_create2 failed \n");
            return -1;
        }
        sleep(70);
    
        // 等待线程退出
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        return 0;
    }
    
    

    线程非正常终止

    1. 主线程退出,全部线程将强行终止。 所以多线程程序主线程是不能退出的。
    2. 在子线程中调调用exit() 函数会终止整个进程。(如果是多进程,子进程退出后,其他进程会继续运行。)
      a. return 和 exit() 的区别. return 会返回主线程。 exit()线程直接退出
    3. 给多线程发信号缺省是终止整个进程。
    4. 在多线程程序中,某一个子线程coredump了,整个进程异常退出。
    线程coredump整个进程异常退出
    void* arg_main2(void* arg) {
        int cnt = *((int*)arg);
        // int* a= new int(23);
        // delete a;
        // delete a;
        for(int i = 0;i < cnt; i++) {
            printf("thread2 sleep %d\n",i);
            
        }
    }
    

    子线程coredump

    终止线程的三种方法

    1. return 和pthread_exit() 的区别?
      a. return 回到线程主函数。不能终止
      b. pthread_exit() 会终止线程。
    2. 线程可以从线程函数中返回,返回值是线程的退出码。
    3. 线程可以被同一进程中其他线程调用pthread_cancel() 取消。
      4.在线程函数中调用pthread_exit() 退出

    线程的参数传递

    1. 创建线程不会保证那个线程的执行顺序
    2. 不能用全局变量代替线程函数的参数。
    3. 数据类型的强制转换。
    4. 如何传递地址参数。
    5. 传递地址参数。
    6. 线程退出状态。

    数据类型的强制转换。

        int ii = 10;
        void *pv = NULL;
        pv = (void*)(long)ii;
        printf("pv = %p \n",pv);
        
        int jj = 0;
        jj = (int)(long)pv;
        printf("jj = %d \n",jj);
    

    具体使用:

    void* arg_main1(void* arg) {
        int cnt = *((int*)arg);
        for(int i = 0;i < cnt; i++) {
            
            printf("thread 1 sleep %d\n",i);
             if(i == 2) func2();
        }
    }
    void* arg_main2(void* arg) {
        int cnt = *((int*)arg);
        // int* a= new int(23);
        // delete a;
        // delete a;
        for(int i = 0;i < cnt; i++) {
            printf("thread2 sleep %d\n",i);
            if(i == 2) func();
        }
    }
    void func() {
        pthread_exit(0);
    }
    void func2() {
        return ;
    }
    
    int main()
    {
    
        ////////////////////////////////////////////
        pthread_t pid1,pid2;
        int arg = 4;
        pthread_create(&pid1,NULL,&arg_main1,(void*)(long)&arg) != 0);
        arg = 7;
        pthread_create(&pid2,NULL,&arg_main2,(void*)(long)&arg) != 0);
        /////////////////////////////////
    
        // 等待线程退出
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        return 0;
        
    }
    

    线程传递地址参数。(把结构体的地址传递给线程函数使用)

    struct stu {
        int age;
        char name[21];
    };
    
    void* arg_main1(void* arg) {
        struct stu *p = (struct stu*)arg;
        printf("age = %d \n",p->age);
        delete p;
    
    }
    void* arg_main2(void* arg) {
        struct stu *p = (struct stu*)arg;
        printf("age = %d \n",p->age);
        delete p;
    }
    
    
    
    int main()
    {
    
        ////////////////////////////////////////////
        struct stu *student = new struct stu;
        student->age = 98;
        strcpy(student->name,"yazh");
    
        pthread_t pid1,pid2;
        int arg = 4;
        pthread_create(&pid1,NULL,&arg_main1,(void*)student);
        
        struct stu *student2 = new struct stu;
        student2->age = 928;
        strcpy(student2->name,"yazh2");
        pthread_create(&pid2,NULL,&arg_main2,(void*)student2);
        /////////////////////////////////
    
        // 等待线程退出
        pthread_join(pid1,NULL);
        pthread_join(pid2,NULL);
        return 0;
        
    }
    

    使用2

    / 本程序演示线程参数的传递(用结构体的地址传递多个参数)。
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    
    void *thmain(void *arg);    // 线程的主函数。
    
    struct st_args
    {
      int  no;        // 线程编号。
      char name[51];  // 线程名。
    };
    
    int main(int argc,char *argv[])
    {
      pthread_t thid=0;
    
      // 创建线程。
      struct st_args *stargs=new struct st_args;
      stargs->no=15;   strcpy(stargs->name,"测试线程");
      if (pthread_create(&thid,NULL,thmain,stargs)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    
      // 等待子线程退出。
      printf("join...\n");
      pthread_join(thid,NULL);  
      printf("join ok.\n");
    }
    
    void *thmain(void *arg)    // 线程主函数。
    {
      struct st_args *pst=(struct st_args *)arg;
      printf("no=%d,name=%s\n",pst->no,pst->name);
      delete pst;
      printf("线程开始运行。\n");
    }
    

    线程退出 pthread_join

    进程和线程的退出状态并不关心。pthread_join 可以拿到返回值,
    进程使用wait

    #include <stdio.h>
    #include <pthread.h>
    #include <malloc.h>
    #include <string.h>
    
    void* arg_main(void* arg);
    
    int main(int argc, char* argv[]) {
        pthread_t pid;
        int thread_param = 4;
        if (pthread_create(&pid,NULL,&arg_main,(void*)&thread_param) !=0) {
            printf("pthread_create failed \n");
            return -1;
        }
        // 等待线程的退出。
        void* ret;
        if (pthread_join(pid,&ret) != 0) {
            printf("pthread_join failed \n");
            return -1;
        }
        if(ret != NULL) {
            printf("msg = %s \n",ret);
        }
        
        puts("end of main() \n");
        free(ret);
    }
    
    
    void* arg_main(void* arg) {
        int i;
        int cnt = *((int*)arg);
        char* msg = (char*)malloc(sizeof(char) * 50);
        strcpy(msg,"hello i am thread\n");
        for(i = 0;i < cnt ;i++) {
            sleep(1);
            printf("pthread running \n");
        }
    
        return (void*)msg;
    }
    

    线程资源的回收,让线程有计划的退出

    进程资源的回收
    进程资源的回收

    线程资源的回收

    默认状态下,线程终止是,不会释放全部资源。一个线程5s,一个线程8s,10s后join获取。全部都能获取资源。
    演示如下:

    // 本程序演示线程资源的回收,用pthread_join非分离的线程。
    // 不能join多次。函数返回失败
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    
    void *thmain1(void *arg);    // 线程主函数。
    void *thmain2(void *arg);    // 线程主函数。
    
    int main(int argc,char *argv[])
    {
      pthread_t thid1,thid2;
    
      // 创建线程。
      if (pthread_create(&thid1,NULL,thmain1,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
      if (pthread_create(&thid2,NULL,thmain2,NULL)!=0) { printf("pthread_create failed.\n"); exit(-1); }
    sleep(10);
      void *ret;
      printf("join...\n");
      int result=0;
      result=pthread_join(thid2,&ret);   printf("thid2 result=%d,ret=%ld\n",result,ret);
      result=pthread_join(thid1,&ret);   printf("thid1 result=%d,ret=%ld\n",result,ret);
      ret=0;
      result=pthread_join(thid2,&ret);   printf("thid2 result=%d,ret=%ld\n",result,ret);
      result=pthread_join(thid1,&ret);   printf("thid1 result=%d,ret=%ld\n",result,ret);
      printf("join ok.\n");
    }
    
    void *thmain1(void *arg)    // 线程1主函数。
    {
      for (int ii=0;ii<3;ii++)
      {
        sleep(1); printf("pthmain1 sleep(%d) ok.\n",ii+1);
      }
      return (void *) 1;
    }
    
    void *thmain2(void *arg)    // 线程2主函数。
    {
      for (int ii=0;ii<5;ii++)
      {
        sleep(1); printf("pthmain2 sleep(%d) ok.\n",ii+1);
      }
      return (void *) 2;
    }
    

    线程的分离

    1. 设置分离之后就不能join了

    用线程清理函数释放资源

  • 相关阅读:
    Asp.net(c#)导出有表格线的Excel
    精妙SQL语句收集
    SQL定时自动备份,并将备份文件加密压缩并自动下载的实现
    如何跨服务器复制表中数据
    两台Sql server的数据同步
    asp.net response.ContentType 下载文件的四种方法
    屏保显示页面控制
    开博白
    新年有感:如何能真正做好项目
    【转】OpenCV图像处理 图像的点运算 ( 灰度直方图 )
  • 原文地址:https://www.cnblogs.com/yaozhenhua/p/16183241.html
Copyright © 2020-2023  润新知