Linux 多线程编程(一)2019-08-05

\color{blue}{多线程}

  1. 线程是程序中完成一个独立任务的完整执行序列,即一个可以调度的实体;进程是资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分配的基本单位.
  2. 一个进程至少拥有一个线程,在同一个进程中的多个线程的内存资源是共享的.由于共享地址空间,所以多线程之间没有通信的必要,但必须要做好数据的同步和互斥.
  3. 并发是指在一个时间段内,多个任务交替进行,虽然看起来像是同时执行,但其实是交替的.

线程控制函数

1.\color{blue}{创建线程}

#include <pthread.h>
int pthread_create(pthread_t* thread,const pthread_attr_t* attr,void*(*start_routine)(void*),void* arg);
//成功时返回值为0,失败则返回错误码

attr参数可以用于设置新线程的属性,给它传NULL,表示使用默认线程属性.start_routine和arg参数分别指定新线程将运行的函数及其参数.
\color{blue}{实例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void* myfunc(void* arg)
{
   //打印子线程的ID
   printf("child thread ID= %ld\n",pthread_self());
   return 0;
}
int main(int argc,const char* argv[])
{
  //创建一个子线程
  //线程ID变量
  pthread_t pthid;
  //返回错误号
  int ret=pthread_create(&pthid,NULL,myfunc,NULL);
  if (ret!=0)
  {
    printf("error number:%d\n",ret);
    //打印错误信息
    printf("%s\n",sterror(ret));
  }
    
  printf("parent thread ID= %ld\n",pthread_self());
  for(int i=0;i<5;i++)
  {
     printf("I=%d\n",i);
  }
  sleep(2);
  return 0;
}

运行结果:

parent thread ID= 140594076149504
I=0
I=1
I=2
child thread ID= 140594068010752
I=3
I=4

2.\color{blue}{线程退出}

 #include <pthread.h>
 void pthread_exit(void *retval);
    // 线程终止

pthread_exit可以通过retval参数向线程的回收者传递其退出的信息.

#include<pthread.h>
int pthread_join(pthread_t thread,void*retval);

pthread_join()函数,以阻塞的方式等待thread指定的线程结束.当函数返回时,被等待线程的资源被收回.thread参数是目标线程的标识符,retval参数则是目标线程返回的退出信息,该函数会一直阻塞,直到被回收的线程结束为止,函数成功时返回值为0,失败则返回错误码.
\color{blue}{实例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>
int num = 100; //堆内存
void *myfunc(void *arg) {
    //打印子线程的ID
    printf("child thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("child I=%d\n", i);
        if (i == 2) {
            //退出携带信息
            pthread_exit(&num);
        }
    }
}
int main(int argc, const char *argv[]) {
    //创建一个子线程
    //线程ID变量
    pthread_t pthid;
    //返回错误号
     int ret = pthread_create(&pthid, NULL, myfunc, NULL);
    if (ret != 0) {
        printf("error number:%d\n", ret);
        //打印错误信息
        printf("%s\n", strerror(ret));
    }
    printf("parent thread ID= %ld\n", pthread_self());
    //阻塞等待子线程的退出,并且回收pcb
    void *ptr = NULL;
    pthread_join(pthid, &ptr);
    printf("number=%d\n", *(int *) ptr);
    for (int i = 0; i < 5; i++) {
        printf("parent I=%d\n", i);
    }
return 0;
}

运行结果:

parent thread ID= 140099126167296
child thread ID= 140099118028544
child I=0
child I=1
child I=2
number=100
parent I=0
parent I=1
parent I=2
parent I=3
parent I=4

3.\color{blue}{线程取消}
有时我们想要异常终止一个线程,即取消线程.

#include <pthread.h>
int pthread_cancel(pthread_t thread);
//成功时返回值为0,失败则返回错误码

不过,接收到取消请求的目标线程可以决定是否允许被取消以及如何取消,这分别由以下两个函数来控制:

#include <pthread.h>
int pthread_setcancelstate(int state, int *oldstate);
int pthread_setcanceltype(int type, int *oldstate);

4.\color{blue}{线程属性设置}
常用的属性:我们一般想要线程在结束时,自动释放其线程资源,自动回收pcb,则就需要给线程设置属性为detach,即线程分离.设置完之后就不需要调用pthread_join再进行线程回收了.
常用的函数与参数:
函数原型: int pthread_detach(pthread_t pthid);
设置属性类型:pthread_attr_t attr;
对线程属性变量初始化:int pthread_attr_init(pthread_attr_t* attr);
设置属性时通用做法:
代码上,可以这样表示:
pthread_t pthid;
pthread_attr_t attr; //线程属性
pthread_attr_init(&attr); //初始化线程属性
pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); //设置线程属性
pthread_create( &pthid, &attr,myfunc, NULL); //建立线程
\color{blue}{实例}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void *myfunc(void *arg) {
    //打印子线程的ID
    printf("child thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("child I=%d\n", i);
        if (i == 2) {
            pthread_exit(NULL);
        }
    }
}
int main(int argc, const char *argv[]) {
    //创建一个子线程
    //线程ID变量
    pthread_t pthid;
    //返回错误号
    //初始化线程属性
    pthread_attr_t attr;
    pthread_attr_init(&attr);

/*  int pthread_attr_init(pthread_attr_t* attr);*/
    //设置分离
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    //创建线程时就设置线程分离
    int ret = pthread_create(&pthid, &attr, myfunc, NULL);
    if (ret != 0) {
        printf("error number:%d\n", ret);
        //打印错误信息
        printf("%s\n", strerror(ret));
    }
    printf("parent thread ID= %ld\n", pthread_self());
    //退出主线程,子线程不受影响
    //由于主线程退出,下面的不执行
    for (int i = 0; i < 5; i++) {
        printf("parent I=%d\n", i);
    }
    sleep(2);
    //释放资源
    pthread_attr_destroy(&attr);
    return 0;
}

运行结果:

parent thread ID= 139976127342336
parent I=0
child thread ID= 139976119203584
child I=0
child I=1
child I=2
parent I=1
parent I=2
parent I=3
parent I=4

5.\color{blue}{循环创建线程}

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
#include<pthread.h>

void *myfunc(void *arg) {
    int num = arg;
    //打印子线程的ID
    printf("%dth child thread ID= %ld\n", num, pthread_self());
    return 0;
}
int main(int argc, const char *argv[]) {
    //创建一个子线程
    //线程ID变量
    pthread_t pthid[5];
    for (int i = 0; i < 5; i++) {  //第四个参数传递的是按值传递,可以对子线程标号,而传地址则不行,公用一个地址,注意此时不在为null了
/*     pthread_create(&pthid[i],NULL,myfunc,(void*)&i);*/
        pthread_create(&pthid[i], NULL, myfunc, (void *) i);
    }
    printf("parent thread ID= %ld\n", pthread_self());
    for (int i = 0; i < 5; i++) {
        printf("I=%d\n", i);
    }
    sleep(2);
    return 0;
}

运行结果:

1th child thread ID= 140415359592192
2th child thread ID= 140415351199488
0th child thread ID= 140415367984896
3th child thread ID= 140415342806784
4th child thread ID= 140415334414080
parent thread ID= 140415376123648
I=0
I=1
I=2
I=3
I=4
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 转自:Youtherhttps://www.cnblogs.com/youtherhome/archive/201...
    njukay阅读 5,560评论 0 52
  • 线程基础 线程是进程的一个执行单元,执行一段程序片段,线程共享全局变量;线程的查看可以使用命令或者文件来进行查看;...
    秋风弄影阅读 4,084评论 0 0
  • 概述 线程和进程本质上来说都属于一个内核调度单元,也就是说都可以作为一条单独的执行路径。但是多进程程序通常有一些限...
    loopppp阅读 3,375评论 0 0
  • 简介 线程创建 线程属性设置 线程参数传递 线程优先级 线程的数据处理 线程的分离状态 互斥锁 信号量 一 线程创...
    第八区阅读 12,726评论 1 6
  • Linux-创建进程与线程用到的函数解析 【1】exit: exit函数可以退出程序并将控制权返回给操作系统,而用...
    Yojiaku阅读 8,966评论 0 2

友情链接更多精彩内容