linux—线程使用

一、概念
线程是进程内部的一条执行序列,一个进程内部至少有一条执行线程。 即就是 main函数的执行体。 进程内部可以有多条线程, main 函数的线程称之为主线程, 其他线程称之为函数线程。 函数线程是由主线程通过系统调用函数创建的。线程可以同时执行。

二、线程与进程的区别

(1)线程是轻量级的进程, 进程是资源分配的最小单位, 线程是调度执行的最小单位。
(2)实体间(进程间,线程间)通信方式的不同

  • 进程间的通信方式有这样几种:
    A.共享内存 B.消息队列 C.信号量 D.有名管道 E.无名管道 F.信号
    G.文件 H.socket
  • 线程间的通信方式上述进程间的方式都可沿用,且还有自己独特的几种:
    A.互斥量 B.自旋锁 C.条件变量 D.读写锁 E.线程信号
    G.全局变量

(3)线程之间的切换需要操作系统做的工作要比进程之间的切换少得多,因此多个线程对资源的需求要远小于多个进程。

三、线程分类

(1)用户级: 在用户空间是多线程的, 内核只识别进程整体。 线程创建、 管理、 销毁都是由用户空间负责, 用户通过调用库函数在完成。
(2) 内核级: 线程的创建、 控制、 销毁都是由内核实现的, 每个线程对内核都是可见的。
(3)组合模型: 一部分是用户级, 一部分内核级线程。 介于内核级和用户级之间, 用户态创建多个线程, 内核看到的也是多个, 只是这是种 m: n 的对应关系。

这里写图片描述

四、线程的创建

#include < pthread.h >
int pthread_create(pthread_t * id , pthread_attr_t * attr , void * (* pthread_fun)(void *), void *arg);

作用:创建一个新线程,类似于创建新进程的fork函数。
返回值:若成功则返回0,否则返回错误编号。

参数解释:
id :线程被创建时,这个指针指向的变量中将被写入一个标志符,用该标志符来引用新线程。
attr: 设置线程属性,一般设置该参数为NULL。
pthread_fun: 线程创建以后所调用的函数地址。
arg: 传递给函数线程的参数。

总结:

  • pthread_create 函数是库函数, 编译的时候必须加载其动态库。(-lpthread)

  • 和写一个普通函数没有明显差别。 只不过在主线程不会调用函数, 而是在创建线程的时候指定函数线程执行的代码入口地址(即就是函数的地址)。 称主函数为主执行序列, 函数的执行为函数线程执行流。

  • 主线程和函数线程同时执行。 一个进程同时执行多个任务。

五、线程终止

如果进程中的任一线程调用了exit,_Exit或者_exit,那么整个进程就会终止。与此类似,如果信号的默认动作是终止进程,那么,把该信号发送到线程会终止整个进程。

单个线程可以通过下列三种方式退出,在不终止整个进程的情况下停止它的控制流。

(1)从启动例程中返回,返回值是线程的退出码
(2)线程可以被同一进程中的其他线程取消
(3)线程调用pthread_exit()

#include< pthread.h >
void pthread_exit(void *rval_ptr);

作用:主线程结束, 函数线程还在运行 。

参数解释:
rval_ptr是一个无类型指针, 指向线程的返回值存储变量。进程中的其他线程可以通过调用 pthread_join函数访问到这个指针。

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

作用: 获取指定线程由 pthread_exit 设置的退出信息。
返回值: 成功则返回0, 否则返回错误编号。

参数解释:
thread: 线程ID。
rval_ptr: 指向返回值的指针(返回值也是个指针)。

说明:

  • 调用线程将一直阻塞, 直到指定的线程调用pthread_exit, 从启动例程返回或被取消。如果线程从它的启动例程返回, rval_ptr包含返回码。如果线程被取消, 由rval_ptr指定的内存单元置为: PTHREAD_CANCELED。如果对返回值不关心, 可把rval_ptr设为NULL。

主线程创建两个函数线程, 第一个负责打印 100 以内的所有的素数, 第二个实现选择排序。 主线程睡眠 100 秒。
 #include< stdio.h>
 #include< stdlib.h>
 #include< assert.h>
 #include< string.h>
 #include< unistd.h>
 #include< pthread.h>

void *pthread_fun1(void *arg)
{
    sleep(1);
    pthread_t id=*(pthread_t*)arg;//获取线程pthread_fun2的id
    pthread_join(id,NULL);//等待线程pthread_fun2的结束
    printf("开始打印100以内的素数\n");
    int i,j;
    for(i=2;i<=100;++i)
    {
        for(j=2; j < i;++j)
        {
            if(i%j==0)
            {
                break;
            }
        }
            if(j>=i)
            {
                printf("%d  ",i);
            }

    }
    printf("\n");

}

void *pthread_fun2(void *arg)
{
    int arr[]={11,52,36,98,74,85,33,65,60,30};
    int len=sizeof(arr)/sizeof(arr[0]);
    printf("对数组元素进行排序\n");
    int i=0,j=0;
    for(; i < len-1;++i)
    {
        int min_index=i;
        for(j=i+1;j < len;++j)
        {
            if(arr[j] < arr[min_index])
                {
                    min_index=j;
                }
            int temp=arr[min_index];
            arr[min_index]=arr[i];
            arr[i]=temp;
        }
    }
        for( i=0;i < len;++i)
        {
            printf("%d  ",arr[i]);
            sleep(1);
            fflush(stdout);
        }   
        printf("\n");
        pthread_exit("sort over");

}

void main()
{
    printf("main start\n");
    pthread_t id1,id2;
    int res=pthread_create(&id1,NULL,pthread_fun1,(void *)&id2);
    assert(res==0);
    res=pthread_create(&id2,NULL,pthread_fun2,NULL);
    assert(res==0);
    printf("pthread create success\n");

    char *p=NULL;
    pthread_join(id1,NULL);//等待线程pthread_fun1退出
 // pthread_join(id2,(void **)&p);//等待线程pthread_fun2结束,并获取结束信息
//  printf("%s\n",p);  //打印fun2的结束信息

    printf("main end\n");
}

这里写图片描述

六、函数线程传递参数

i. 传值
将变量的值强转成 void* , 函数线程中, 对 arg 的值强转成变量的类型。
ii. 传地址
将变量的地址强转成 void*, 函数线程中, 对 arg 的值强转成变量类型的指针,再去取值。

  • 如果是传递变量地址, 获取变量值时, 必须考虑变量的值是否被改变。

七、线程间的数据共享

全局变量:共享
栈区数据 :不共享
堆区:共享
文件: 共享(同一个进程的线程, 使用一个 PCB, 只要线程能拿到打开
的文件的文件描述符, 就可以通过文件描述符操作文件。)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值