当前位置: 首页 > article >正文

学习c++多线程前,回顾一下Linux的多线程

更多详细内容, 可以查看 作者博客的 linux 网络编程专栏

文章目录

    • 循环创建n个子线程
      • 并 循环回收---难点
      • 1-loop-pthread.c
      • 2-pthread-join-error.c
      • 3-pthread-join-true.c
    • 使用 pthread_cancel函数取消线程
      • 使用默认系统调用 作为取消点
      • 使用 指定的pthread_testcancel()作为取消点
      • pthread-cancel.c
    • 设置 线程分离, 并 jion回收, 查看出错
      • pthread-detach.c
    • 使用线程 属性设置 分离态
      • pthread-attr.c
    • 简单的 互斥锁(4个)
      • 不使用锁的效果
      • 正常加锁解锁
      • tyrlock 替换进去看效果
      • 营造死锁的 问题
      • 1-mutex-no-lock.c
      • 2-mutex-lock.c
      • 3-mutex-trylock.c
      • 4-mutex-si.c
    • 条件变量---重点
      • 生产者和消费者模型
      • producer-customer.c

循环创建n个子线程

并 循环回收—难点

1-loop-pthread.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// 循环创建子线程, 并验证 是不是共享全局变量

int var = 100;


void *tfn(void *arg)
{
    int i = (int)arg;
    var = 400;
    printf("thread--%d: pid = %d, tid is %lu, var = %d\n", i, getpid(), pthread_self(), var);
    sleep(2);
    printf("test ----%d\n", i);
    return NULL; 
}

int main(int argc, char *argv[])
{   
    pthread_t tid;
    int i=0;
    var = 200;
    while(i<10)
    {
        int ret = pthread_create(&tid, NULL, tfn, (void*)i);
        // int ret = pthread_create(&tid, NULL, tfn, (void*)&i);   // 容易导致 内容错乱
        if(ret < 0)
        {
            fprintf(stderr, "pthread error: %s\n", strerror(ret));
            exit(1);
        }
        i++;
        sleep(1);
    }
    printf("main: pid is %d, tid is %lu, var = %d\n", getpid(), pthread_self(), var);
    
    pthread_exit((void*)0);  // 会退出 当前线程, 也就是只退出了 主线程
    // return 0;//线程不能使用这个   会出现 子线程还未结束, 整体 进程 就退出
}


2-pthread-join-error.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// pthread_join 测试
// 错误示范, 局部变量 地址 会被释放, 所以一直返回 0

int var = 100;


void *tfn(void *arg)
{
    int i = (int)arg;
    var = 400;
    printf("thread--%d: pid = %d, tid is %lu, var = %d\n", i, getpid(), pthread_self(), var);
    sleep(2);
    printf("test ----%d\n", i);
    int *r=&i;
    return (void*)r; 
}

int main(int argc, char *argv[])
{   
    pthread_t tid;
    int i=0;
    var = 200;
    
    int *tidret;  

    while(i<10)
    {
        int ret = pthread_create(&tid, NULL, tfn, (void*)i);
        if(ret < 0)
        {
            fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
            exit(1);
        }
        
        ret = pthread_join(tid, (void **)&tidret);
        if(ret < 0)
        {
            fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
            exit(1);
        }
        printf("child %d return %d\n",i, *tidret);

        i++;
        sleep(1);
    }
    printf("main: pid is %d, tid is %lu, var = %d\n", getpid(), pthread_self(), var);
    
    pthread_exit((void*)0);  // 会退出 当前线程, 也就是只退出了 主线程
    // return 0;//线程不能使用这个   会出现 子线程还未结束, 整体 进程 就退出
}


3-pthread-join-true.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// pthread_join 测试
// 错误示范, 局部变量 地址 会被释放, 所以一直返回 0
// 这是正确示范   使用malloc 可以防止销毁
 
int var = 100;


void *tfn(void *arg)
{
    int i = (int)arg;
    var = 400;
    printf("thread--%d: pid = %d, tid is %lu, var = %d\n", i, getpid(), pthread_self(), var);
    sleep(1);
    printf("test ----%d\n", i);
    int *r = malloc(sizeof(int *));   
    *r = i;   // 不能传地址, 地址会释放, 传递值  注意不是  r=i
    return (void*)r; 
}

int main(int argc, char *argv[])
{   
    pthread_t tid;
    int i=0;
    var = 200;
    
    // int *tidret;   // 外部容易 内存 泄漏

    while(i<10)
    {
        int *tidret; 

        int ret = pthread_create(&tid, NULL, tfn, (void*)i);
        if(ret < 0)
        {
            fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
            exit(1);
        }
        
        ret = pthread_join(tid, (void **)&tidret);
        if(ret < 0)
        {
            fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
            exit(1);
        }
        printf("child %d return %d\n",i, *tidret);
        free(tidret);
        i++;
        sleep(1);
    }
    printf("main: pid is %d, tid is %lu, var = %d\n", getpid(), pthread_self(), var);
    
    pthread_exit((void*)0);  // 会退出 当前线程, 也就是只退出了 主线程
    // return 0;//线程不能使用这个   会出现 子线程还未结束, 整体 进程 就退出
}


使用 pthread_cancel函数取消线程

使用默认系统调用 作为取消点

使用 指定的pthread_testcancel()作为取消点

pthread-cancel.c

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>
void *tfn1(void *arg)
{
    printf("thread 1 returning\n");
    return (void *)111;
}
void *tfn2(void *arg)
{
    printf("thread 2 exiting\n");
    pthread_exit((void *)222);
}
void *tfn3(void *arg)
{
    while (1)
    {
        // printf("thread 3: I'm going to die in 3 seconds ...\n");  
        // sleep(1); //这两句 会进入系统调用, 到达 取消点, 若没有这两句, 需手动添加取消点
        pthread_testcancel(); //自己添加取消点*/
    }
    return (void *)666;
}
int main(void)
{
    pthread_t tid;
    void *tret = NULL;
    pthread_create(&tid, NULL, tfn1, NULL);
    pthread_join(tid, &tret);
    printf("thread 1 exit code = %d\n\n", (int)tret);


    pthread_create(&tid, NULL, tfn2, NULL);
    pthread_join(tid, &tret);
    printf("thread 2 exit code = %d\n\n", (int)tret);


    pthread_create(&tid, NULL, tfn3, NULL);
    sleep(3);
    pthread_cancel(tid);
    pthread_join(tid, &tret);
    printf("thread 3 exit code = %d\n", (int)tret);


    return 0;
}

设置 线程分离, 并 jion回收, 查看出错

pthread-detach.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

void *tf(void *arg)
{
    printf("exit ----- \n");
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid;

    int ret = pthread_create(&tid, NULL, tf, NULL);
    if(ret != 0)
    {
        fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
        exit(1);
    }

    ret = pthread_detach(tid);
    if(ret != 0)
    {
        fprintf(stderr, "pthread_detach error: %s\n", strerror(ret));
        exit(1);
    }

    sleep(2);  // 不等待,看不出区别
    ret = pthread_join(tid, NULL);
    if(ret != 0)
    {
        fprintf(stderr, "pthread_join error: %s\n", strerror(ret));
        exit(1);
    }
    printf("main----\n");

    pthread_exit(NULL);
}


使用线程 属性设置 分离态

pthread-attr.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

void *fn(void *arg)
{
    printf("child-----\n");
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid;
    
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    int ret = pthread_create(&tid, &attr, fn, NULL);
    if(ret != 0)
    {
        fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
        exit(1);
    }

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


    pthread_attr_destroy(&attr);
    pthread_exit(NULL);
}


简单的 互斥锁(4个)

读写锁差不多,不写案例

不使用锁的效果

正常加锁解锁

tyrlock 替换进去看效果

营造死锁的 问题

1-mutex-no-lock.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// 无锁, 多个线程 会抢占资源, 不能按照顺序打印

void *fn(void *arg)
{
    while(1)
    {
        printf("hello--2\n");
    sleep(rand()%3);
    printf("world--2\n");
    sleep(rand()%3);
    }
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid;
    srand(time(NULL));

    int ret = pthread_create(&tid, NULL, fn, NULL);
    if(ret < 0 )
    {
        fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
        exit(1);
    }
    while(1)
    {
        printf("HELLO--1\n");
        sleep(rand()%3);
        printf("WORLD--1\n");
        sleep(rand()%3);
    }
    

    pthread_join(tid, NULL);
    pthread_exit(NULL);

}

2-mutex-lock.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// 无锁, 多个线程 会抢占资源, 不能按照顺序打印
// 加锁,  会 一个线程 一会占用 

pthread_mutex_t mutex;  // 定义一个全局, 可以使得 所有线程 都能加锁解锁

void *fn(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        printf("hello--2\n");
        sleep(rand()%3);
        printf("world--2\n");
        pthread_mutex_unlock(&mutex);
        sleep(rand()%3);
    }
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid;
    srand(time(NULL));
    pthread_mutex_init(&mutex, NULL);

    int ret = pthread_create(&tid, NULL, fn, NULL);
    if(ret < 0 )
    {
        fprintf(stderr, "pthread_create error: %s\n", strerror(ret));
        exit(1);
    }
    while(1)
    {
        pthread_mutex_lock(&mutex);
        printf("HELLO--1\n");
        sleep(rand()%3);
        printf("WORLD--1\n");
        pthread_mutex_unlock(&mutex);
        sleep(rand()%3);
        
    }
    
    
    pthread_join(tid, NULL);
    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);

}


3-mutex-trylock.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

// 无锁, 多个线程 会抢占资源, 不能按照顺序打印
// 加锁,  会 一个线程 一会占用 

pthread_mutex_t mutex;  // 定义一个全局, 可以使得 所有线程 都能加锁解锁

void *fn(void *arg)
{
    if((pthread_mutex_trylock(&mutex) == 0))
    {
        printf("thread %ld: acquire lock\n", (long)arg);
        sleep(2);
        pthread_mutex_unlock(&mutex);
    }
    else
    {
        printf("thread %ld: none lock\n", (long)arg);
    }
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid,tid2;
    srand(time(NULL));
    pthread_mutex_init(&mutex, NULL);

    int ret = pthread_create(&tid, NULL, fn, (void *)1);
    pthread_join(tid, NULL);   // 这个位置决定了 1结束, 2才会创建, 因此都会打印 拿到锁

    ret = pthread_create(&tid2, NULL, fn, (void *)2);
    // pthread_join(tid, NULL);
    pthread_join(tid2, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);

}


4-mutex-si.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>



// 反复加锁, 会死锁, 一直阻塞

pthread_mutex_t mutex;  // 定义一个全局, 可以使得 所有线程 都能加锁解锁

void *fn(void *arg)
{
    if((pthread_mutex_lock(&mutex) == 0))
    {
        printf("thread %ld: acquire lock\n", (long)arg);
        sleep(2);
        // pthread_mutex_unlock(&mutex);
    }
    else
    {
        printf("thread %ld: none lock\n", (long)arg);
    }
    return NULL;
}


int main(int argc, char *argv[])
{   
    pthread_t tid,tid2;
    srand(time(NULL));
    pthread_mutex_init(&mutex, NULL);

    int ret = pthread_create(&tid, NULL, fn, (void *)1);
    pthread_join(tid, NULL);   // 这个位置决定了 1结束, 2才会创建, 因此都会打印 拿到锁

    ret = pthread_create(&tid2, NULL, fn, (void *)2);
    // pthread_join(tid, NULL);
    pthread_join(tid2, NULL);

    pthread_mutex_destroy(&mutex);
    pthread_exit(NULL);

}


条件变量—重点

生产者和消费者模型

producer-customer.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>

pthread_mutex_t mutex;
pthread_cond_t cond_product;

struct product *head;
int i=10,j=10;
struct product
{
    int num;
    struct product *next;
};

void Prr(int ret, char *str)
{
    if(ret < 0)
    {
        fprintf(stderr, "%s error : %s\n",str, strerror(ret));
        exit(1);
    }
}

void *Customer(void *arg)
{
    struct product *stc;
    
    while(i!=0)
    {
        pthread_mutex_lock(&mutex); 
        while(head == NULL) // 为空, 则条件变量, 阻塞等待   不使用if, 解除阻塞后, 需要再次检查, 若是多个customer, 可能为空
        {
            pthread_cond_wait(&cond_product, &mutex);
        }
        stc = head;
        head = head->next;
        printf("customer ------ %d\n", stc->num);
        free(stc);
        pthread_mutex_unlock(&mutex);
        sleep(rand()%4);
        i--;
    }
    return NULL;
}

void *Productor(void *arg)
{
    struct product *st;
    while(j!=0)
    {
        st = malloc(sizeof(struct product));
        st->num = rand()%1000;
        printf("product ------ %d\n", st->num);
        
        pthread_mutex_lock(&mutex);  // st 链表作为 共享资源, 因此改变链表需要加锁

        st->next = head;
        head = st;  // 头插法 head要一直保持在 开头,  新元素 next先指向head, head再指向新元素

        pthread_mutex_unlock(&mutex);
        pthread_cond_signal(&cond_product);  // 解锁并 唤醒
        sleep(rand()%4);
        j--;
    }
    return NULL;
}



int main(int argc, char *argv[])
{   
    pthread_t tid1,tid2;
    
    int ret = pthread_create(&tid1, NULL, Productor, NULL);  // 生产和消费的顺序, 决定了 在哪里  malloc
    Prr(ret,"create");
    ret = pthread_create(&tid2, NULL, Customer, NULL);
    Prr(ret, "create");
    

    pthread_join(tid1, NULL);
    pthread_join(tid2, NULL);
        
    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond_product);
    pthread_exit(NULL);
}



http://www.kler.cn/a/597868.html

相关文章:

  • 圆弧插补相关算法汇总(C++和ST源代码)
  • CUDA 学习(4)——CUDA 编程模型
  • Android 系统进程启动Activity方法说明
  • 爬虫:scrapy面试题大全(60个scrapy经典面试题和详解)
  • 多线程编程中什么时候使用锁和原子操作
  • C#单例模式
  • Redis集群模式(优缺点)
  • AI重构工程设计、施工、总承包行业:从智能优化到数字孪生的产业革命
  • 群体智能优化算法-蛾火焰优化算法(Moth-Flame Optimization Algorithm,含Matlab源代码)
  • uboot(bootrom的作用)
  • [快乐学坊_2] 后端api测试
  • 数据结构篇——二叉树的存储与遍历
  • UnoCSS极速入门:下一代原子化CSS引擎实战指南
  • CVPR 2025 | 文本和图像引导的高保真3D数字人高效生成GaussianIP
  • Gradle/Maven 本地仓库默认路径迁移 (减少系统磁盘占用)
  • 【中文翻译】第1章-The Algorithmic Foundations of Differential Privacy
  • OTN(Optical Transport Network,光传输网络)
  • 机器人的位姿变换左乘与右乘
  • The First Indoor Pathloss Radio Map Prediction Challenge
  • 数组作为哈希表的妙用:寻找缺失的第一个正数