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());
相关推荐
黑客学长-刘备4 分钟前
终于有人把网络安全就业方向一口气讲清了(非常详细)零基础入门到精通,收藏这一篇就够了
java·运维·服务器·网络·python·安全·web安全
小爬虫程序猿5 分钟前
Java爬虫:在1688上“照片快递”上传图片
java·开发语言·爬虫
Json_181790144806 分钟前
小红书笔记详情API接口系列(概述到示例案例)
开发语言·python
热爱生活热爱你27 分钟前
Qt5 读写共享内存,已验证,支持汉字的正确写入和读取
开发语言·qt
QEasyCloud20221 小时前
简道云和企业微信数据同步集成案例
java·大数据·前端
TheoBrien1 小时前
JUC(java.util.concurrent) 的常⻅类
java·开发语言
淡淡蛋痛1 小时前
D3.js 入门指南
开发语言·javascript·信息可视化
wrx繁星点点1 小时前
创建型模式-建造者模式:构建复杂对象的优雅解决方案
java·开发语言·数据结构·数据库·spring·maven·建造者模式
王大锤43911 小时前
golang的多表联合orm
开发语言·后端·golang
m0_688118422 小时前
Web(B/S架构)
java·servlet