weiqi7777

进击吧,linux(十九) 多线程编程

0
阅读(3941)

 

           线程,被称为轻量级进程,相比多进程,有以下两点不同:

1、  线程和创建他的进程共享代码段、数据段

2、  线程拥有自己独立的栈


同样,对于多线程编程学习,也是基于几个函数的学习。

11.1 创建线程

11.1.1 函数名

    pthread_create

11.1.2 函数原形

    int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *),void *arg)

11.1.3 函数功能

    创建新的线程

11.1.4 所属头文件

    <pthread.h>

           创建线程需要链接pthread  gcc –lpthread

            

11.1.5 返回值

    成功:0

    失败:错误编码

    -EAGAIN: 没有资源创建新线程

    -EINVAL: 无效的属性设置

    -EPERM:没有权限设置属性中的一些参数

11.1.6 参数说明

    thread:  线程ID,创建成功的话,*thread会保存创建的线程的ID

    attr:  指定创建线程的属性,如果为NULL,使用默认属性

    start_routine: 创建的线程执行的入口函数

    arg:       线程入口函数的参数,可以为NULL

11.1.7 示例代码

 

11.2 等待线程结束

11.2.1 函数名

    pthread_join

11.2.2 函数原形

    Int pthread_join(pthread_t thread, void **retval)

11.2.3 函数功能

    等待thread的线程结束

11.2.4 所属头文件

    <pthread.h>

    需要链接pthread  gcc –lpthread

11.2.5 返回值

    成功:0

    失败: 错误编码

    -EDEADLK: deadlock was detected

    -EINVAL:   线程不可等待

    -ESRCH: 线程ID不正确

11.2.6 参数说明

    thread 要等待结束的线程ID

    retval 保存线程时退出的状态,一般为NULL,不保存

11.2.7 示例代码

 

11.3 退出线程

11.3.1 函数名

    pthread_exit

11.3.2 函数原形

    void pthread_exit(void *retval)

11.3.3 函数功能

结束线程

11.3.4 所属头文件

    <pthread.h>

    需要链接pthread  gcc –lpthread

11.3.5 返回值

    函数没有返回

11.3.6 参数说明

    retval 保存退出的返回值

11.3.7 示例代码

 

下面,就编写代码来对上面几个函数进行学习。

代码实现的功能,就是创建3个线程,分别传入三个参数,然后各个线程打印自己的内容。


#include "pthread.h"
#include "stdio.h"
 

void *fun_1(void  *str)
{
    //将输入的参数强制转化成char *类型
    printf("%s\n",(char *)str);
    sleep(2);
    pthread_exit(NULL);
}
 

void *fun_2(void  *a)
{
    //将输入的参数强制转化成int *类型
    printf("%d\n",*(int *)a);
    sleep(3);
    pthread_exit(NULL);
}
 

void *fun_3(void *nul)
{
    printf("welcome to weiqi7777 blog\n");
    sleep(4);
    pthread_exit(NULL);
}
 

int main()
{
    pthread_t thread[3];
    int arg=5;
    //创建线程1
    pthread_create(&thread[0],NULL,fun_1,(void *)"hello weiqi7777");
    //创建线程2
    pthread_create(&thread[1],NULL,fun_2,(void *)&arg);
    //创建线程3
    pthread_create(&thread[2],NULL,fun_3,NULL);
   
    //等待线程1结束
    pthread_join(thread[0],NULL);
    //等待线程2结束
    pthread_join(thread[1],NULL);
    //等待线程3结束
    pthread_join(thread[2],NULL);
   
    exit(0);
}


这里,要注意的有几个地方。

1、  创建线程的时候,第一个参数是传入线程标识符的地址,所以在这里是&thread[0]

2、  创建线程的最后一个是传入的参数,按照规定的,这个参数的类型是void *,所以在这里对传入的参数进行强制类型转化,防止编译有警告

3、  对于线程的函数,类型是void *(*)(void *)类型的,所以线程的函数要按照这个类型进行定义,不然会报错或者警告

4、  线程执行完毕后,要调用pthread_exit进行线程的退出

5、  主进程中,一定要等待所有线程执行完毕后,才能退出程序,否则当退出程序后,没有执行完毕的线程就直接被退出了。


执行程序,首先是用gcc –lpthread对程序进行编译,然后再执行。发现,执行两次的结果不一样,可以看出,对于多线程,执行的顺序不是固定的。不是谁先创建就先执行哪一个线程。

clip_image002


以上,就是多线程编程的学习了,但是也只是学习了多线程的基本使用,但是问题来了,因为多线程是共享主进程的数据段,那如果多个线程同时对一个数据进行操作的话,又怎么处理了,按照之前学习的,肯定就想到了信号量的互斥,但是在多线程中,是不用这个信号量的,是使用互斥锁。