当前位置:   article > 正文

c++多线程项目 - 认识线程_c++ 多线程项目

c++ 多线程项目

线程作用特点,为啥要有这个东西

  • 轻量,大部分资源共享父线程,所以创建起来花费相比进程低
  • 通信方便,因为堆的资源是共享的,所以子线程可以方便的通信
  • 当父线程结束时,子线程就结束了,与进程不一样
  • 一个进程可以有多个线程
  • 不共享的资源:
    • 线程id
    • 信号掩码
    • error变量
    • 实时调度策略和优先级
    • 栈、本地变量

创建线程

线程库不属于标准库所以编译链接的时候需要指定线程库 -pthread


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

// callback function
void* callback(void* arg) {
    printf("child thread...\n");
    printf("arg value: %d\n", *(int *)arg);
}

int main() {
    pthread_t tid;
    int num  = 10;
    // create a child thread
    int ret = pthread_create(&tid, NULL, callback, (void *)&num);
    if(ret != 0) {
        char* errstr = strerror(ret);
        printf("error: %s\n", errstr);
    }
    sleep(1); // what will happen, if delete this statement
    return 0;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

pthred_exit/pthread_self

  1. void pthread_exit(void *retval)
  • 功能: 终止一个线程,但是不会带走其子线程,
  • 参数:一个指针用于接收子线程返回值,需要join
  1. pthread_t pthread_self(void)
  • 功能: 获取当前线程pid

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

// callback function
void* callback(void* arg) {
    sleep(1);
    printf("child thread...\n");
    printf("arg value: %d\n", *(int *)arg);
    pthread_exit(0); // return 0;
}

int main() {
    pthread_t tid;
    int num  = 10;
    // create a child thread
    int ret = pthread_create(&tid, NULL, callback, (void *)&num);
    if(ret != 0) {
        char* errstr = strerror(ret);
        printf("error: %s\n", errstr);
    }
    printf("tid: %ld, main thread id: %ld\n", tid, pthread_self());
    // 终止一个线程
    // 不会带走其子线程
    pthread_exit(NULL);
    
    printf("main thread exit\n");

    return 0;

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

join

int pthread_join(pthread_t thread, void **retval);

  • 功能: 和一个已经终止的线程进行连接,回收子线程的资源
  • 特点: 阻塞函数,调用一次只能回收一个子线程
  • 参数:
    • thread: 需要回收的子线程的ID
    • retval: 接收子线程退出的返回值
  • 返回值
    • 0: 成功
    • 非0: 对应的错误号
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void* callBack(void* num) {
    puts("I'm child pthread");
    printf("%d\n", *(int*)num);
    printf("pthread_id: %ld\n", pthread_self());
    // int* val = new int(10);
    int val = 10;
    return (void*) 10;
}
int main() {
    int num = 10;
    
    pthread_t* pid;
    int ret = pthread_create(pid, NULL, callBack, (void*)&num);
    if(ret != 0) {
        puts(strerror(ret));
    }
    int* val;
    if(ret != 0) {
        puts(strerror(ret));
    }
    // 需要修改val指针的指向
    pthread_join(*pid, (void**) &val);
    printf("%d\n", *val);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

detach

int pthread_detach(pthread_t thread)

  • 功能: 分离一个线程。被分离的线程在终止时,会自动被释放资源返回给系统,
  • 注意:不能多次分离,不能去连接一个分离的线程;分离的线程还是属于原进程,当main 结束return 时,也就是进程结束时,还是会带走该线程。怎么验证这一点呢?可以输出子线程的pid
  • 参数: 需要分离的线程的ID
  • 返回值:
    • 0: 成功
    • 非0: 错误号


#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
// callback function
void* callback(void* arg) {
    sleep(1);    
    printf("child thread...\n");
    printf("my pid = %d\n", getpid());
    printf("arg value: %d\n", *(int *)arg);
   // 当main return时,如果不带走子线程,那么这个文件会被创建
    int fd = open("/home/dyj/byMyself/basic/thread/in.txt", O_CREAT | O_RDWR, 0664);
    if(fd == -1) {
        perror("open");
    }
    write(fd, "123", 4);
    close(fd);
}

int main() {
    pthread_t tid;
    int num  = 10;
    // create a child thread
    int ret = pthread_create(&tid, NULL, callback, (void *)&num);

    if(ret != 0) {
        char* errstr = strerror(ret);
        printf("error: %s\n", errstr);
    }
    pthread_detach(tid);
    printf("%d\n",(int)getpid());
    printf("%ld\n %ld\n", tid, pthread_self());
    puts("father thread die");
    // sleep(1); 


    pthread_exit(0);
    return 0; // 有前一句,这句不会被执行

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

cancel

int pthread_cancel(pthread_t thread);

  • 功能:
    • 取消线程(让线程终止),不是立即取消,是到可取消点才能取消
    • 如果取消的是main线程,同样不会立即回收资源,而是停止,等所有线程结束后,再回收资源
  • 参数: 待取消点线程id
  • 返回值:
puts("cancelled");

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

void* callBack(void* arg) {

    for(int i = 0; i < 5; i++) {
        printf("I'm pthread, My tid= %ld\n", pthread_self());
    }
}

int main() {

    pthread_t tid;

    int ret = pthread_create(&tid, NULL, callBack, NULL);
    if(ret != 0) {
        puts(strerror(ret));
        _exit(0);
    }
    
    if(ret != 0) {
        puts(strerror(ret));
        _exit(0);
    }
    ret = pthread_cancel(tid);

    ret = pthread_cancel(pthread_self());
    puts("cancelled");//有输出,说明不是立即取消
    puts("cancelled");
    puts("cancelled");
    puts("cancelled");
    puts("cancelled");
    puts("cancelled");
    

    for(int i = 0; i < 5; i++) {
        printf("I'm man thread, My tid= %ld\n", pthread_self());
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

attr

体验设置线程的attr属性

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

void* callback(void* arg) {
    puts("Im a pthread");
}

int main() {

    pthread_attr_t attr;
    pthread_attr_init(&attr);

    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_t tid;
    
    int ret = pthread_create(&tid, &attr, callback, NULL);
    if(ret != 0) {
        puts(strerror(ret));
        _exit(0);
    }

    size_t size;
    pthread_attr_getstacksize(&attr, &size);
    printf("thread stack size: %ld\n", size);

    printf("tid: %ld, main thread id: %ld\n", tid, pthread_self());

    pthread_attr_destroy(&attr);
    pthread_exit(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

问题

  1. 为什么需要join/detach线程,如果我不这样,有哪些资源是不可回收的或者释放的呢?子线程正常结束时,哪些资源是不能自己释放的?
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号