Linux:线程及其控制

我们已经学了线程的创建,现在要学习线程的控制

线程等待

我们来先写一个没有线程等待的代码:

pthcon.c:

复制代码
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
   while(1){
    printf("pthread is running\n");
    sleep(1);
   }
}
int main(){
    pthread_t tid;
    int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
    if(n!=0){
        perror("creat failed\n");
        return -1;
    }
    if(n==0){
        printf("main thread wait success\n");
    }

    return 0;
}

可以看到我们的线程每次运行的结果都是随机的,有时候主线程还没运行完,gopthraed会先运行完;就像在进程中,我们更期望的子进程先运行完,所以我们更希望mian线程后退出

所以线程等待的正确用法:

复制代码
while :; do ps -aL;sleep 1;done

pthcon.c:

复制代码
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
    int cnt=5;
    while(cnt--){
    printf("pthread is running\n");
    sleep(1);
   }
}
int main(){
    pthread_t tid;
    int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
    if(n!=0){
        perror("creat failed\n");
        return -1;
    }
    n=pthread_join(tid,NULL);
    printf("maim pthread begin\n");
    if(n==0){
        printf("main thread wait success\n");
    }

    return 0;
}
复制代码
#include <pthread.h>
int pthread_join(pthread_t thread, void **rval_ptr);
// 返回:若成功返回0,否则返回错误编号

调用pthread_join函数的线程将会一直阻塞,直到我们指定调用的线程(也就是代码里的gopthread)从main中调用pthread_exit、从例程中返回或者被取消,它不停止,main就一直阻塞。如果我们的gopthread从main中返回,那么rval_ptr将包含返回码;如果线程被取消,则由rval_ptr指定的内存单元就被置为PTHREAD_CANCELED

①可以通过调用pthread_join自动把线程置于分离状态,这样资源就可以恢复。如果线程已经处于分离状态,pthread_join调用就会失败,返回EINVAL。

②如果对线程的返回值不感兴趣,可以把rval_ptr置为NULL。在这种情况下,调用pthread_join函数将等待指定的线程终止,但并不获得线程的终止状态。

例如我们调用两次该函数:

复制代码
#include<stdio.h>
#include<pthread.h>
void* gopthread(void* arg){
    int cnt=5;
    while(cnt--){
    printf("pthread is running\n");
    sleep(1);
   }
}
int main(){
    pthread_t tid;
    int n=pthread_create(&tid,NULL,gopthread,(void*)"pthread 1");
    if(n!=0){
        perror("creat failed\n");
        return -1;
    }
    n=pthread_join(tid,NULL);
        n=pthread_join(tid,NULL);
        printf("n==%d\n",n);
    printf("maim pthread begin\n");
    if(n==0){
        printf("main thread wait success\n");
    }

    return 0;
}

这时候我们的线程已经处于分离状态,但又调用了一次该函数,所以会报错,3是错误码

pthread_create里第三个参数,我们在前文中提到用结构体,如何把结构体的地址传过去:

复制代码
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
typedef struct ThreadData{
    char name[20];
    int num;
}ThreadData;//定义结构体

void* gopthread(void* arg){
    int cnt=5;
    while(cnt--){
    printf("pthread is running\n");
    sleep(1);
   }
}
int main(){
    pthread_t tid;
    ThreadData *td=(ThreadData*)malloc(sizeof(ThreadData));//防止两个线程同时访问同一片内存,破坏坏主线程的完整性及独立性
    strcpy(td->name,"thread-1");
    td->num=1;
    int n=pthread_create(&tid,NULL,gopthread,(void*)&td);//传参
    if(n!=0){
        perror("creat failed\n");
        return -1;
    }
    n=pthread_join(tid,NULL);
    printf("n==%d\n",n);
    printf("maim pthread begin\n");
    if(n==0){
        printf("main thread wait success\n");
    }
    free(td)
;    return 0;
}

集贸,这次我一定要解决你

哦原来是没链接上主机

如果我们想创建多线程呢?

复制代码
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void*  gopthread(void* args){
    char* name=(char*)args;
    while(1){       
        printf("%s pthread is running\n",name);
        sleep(1);
    }
    return NULL;
}


int main(){
    char names[10][128];
    pthread_t tids[10];
    for(int i=1;i<=10;i++){
        snprintf(names[i],sizeof(names[i]),"thread-%d",i);
        pthread_create(&tids[i], NULL,gopthread,names[i]);
    }
    sleep(1000);
    return 0;
}

我们发现即使我们按顺序创建线程,但是却不能按顺序调度线程

没事,退出去有顺序就好(加入线程等待)

复制代码
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void*  gopthread(void* args){
    char* name=(char*)args;
     
        printf("%s pthread is running\n",name);
        sleep(1);
    
    return args;
}


int main(){
    char names[10][128];
    pthread_t tids[10];
    for(int i=1;i<=10;i++){
        snprintf(names[i],sizeof(names[i]),"thread-%d",i);
        pthread_create(&tids[i], NULL,gopthread,names[i]);
    }
    for(int i=1;i<=10;i++){
        void* name=NULL;
        pthread_join(tids[i],&name);
        printf("%s quit...\n",(char*)name);
    }
    return 0;
}

我勒个数组越界

复制代码
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
void*  gopthread(void* args){
    char* name=(char*)args;
     
        printf("%s pthread is running\n",name);
        sleep(1);
    
    return args;
}


int main(){
    char names[10][128];
    pthread_t tids[10];
    for(int i=0;i<10;i++){
        snprintf(names[i],sizeof(names[i]),"thread-%d",i);
        pthread_create(&tids[i], NULL,gopthread,names[i]);
    }
    for(int i=0;i<10;i++){
        void* name=NULL;
        pthread_join(tids[i],&name);
        printf("%s quit...\n",(char*)name);
    }
    return 0;
}

这下好了

线程终止

main函数结束,main线程结束,也就代表着进程结束了

所以我们得保证其他线程结束的时候,主线程再结束

return通常应用于一个函数的正常终止,exit可以结束整个程序,通常用来在异常情况下立即终止程序

复制代码
#include <pthread.h>
int pthread_exit(void *rval_ptr);

rval_ptr:是一个无类型指针,与传给启动例程的单个参数类似。进程中的其他线程可以通过调用pthread_join函数访问到这个指针。

使用的时候调用这个接口就好了

线程取消

取消线程的前提:线程存在(存在才能被取消)

复制代码
#include <pthread.h>
int pthread_cancel(pthread_t thread);
Compile and link with -pthread.

取消后线程的返回值是-1

线程分离

join函数是等待线程退出,那么我们可不可以让线程自己退出

答案是线程分离

复制代码
#include <pthread.h>
int pthread_detach(pthread_t thread);

如果一个线程被创建出来,那么默认他是需要被join的

如果该线程被分离了,那么就不需要被join了

线程可以自己分离自己,也可以由主线程分离,只要存在就可以分离

本函数通常由想让自己脱离的线程使用,就如以下语句:

复制代码
pthread_detach(pthread_self());
相关推荐
许彰午5 小时前
14_Java泛型完全指南
java·windows·python
智慧物业老杨5 小时前
司法绿色通道下的物业纠纷数智化解决方案——基于“三优先“机制的全流程技术落地实践
java·django
2601_961194026 小时前
2026初级会计实务公式总结大全|计算题公式手册PDF
java·spring·eclipse·pdf·tomcat·hibernate
做个文艺程序员6 小时前
第1篇:K8s 核心概念精讲:Pod、Deployment、Service 与 Namespace——Java 开发者快速上手指南
java·云原生·容器·kubernetes·容器编排
小欣加油8 小时前
leetcode3751 范围内总波动值I
java·数据结构·c++·算法·leetcode
代码中介商8 小时前
C++左值与右值:核心判断法则详解
开发语言·c++
闪电悠米8 小时前
黑马点评-Redisson-01_why_redisson
java·服务器·网络·数据库·缓存·wpf
星轨zb8 小时前
LangChain4j 集成 Spring Boot:会话记忆 NPE 的根源与 ChatMemoryProvider 正确配置
java·spring boot·后端·langchain4j
JAVA9658 小时前
JAVA面试-并发篇 05-并发包AQS队列实现原理是什么
java·开发语言·面试
JAVA面经实录9178 小时前
RocketMQ全套学习知识手册
java·kafka·rabbitmq·rocketmq