linux 多线程 pthread库 API

线程的创建、退出、等待

线程的创建:

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

参数介绍:
pthread_t *thread ------------------------用于标识一个线程
const pthread_attr_t *attr--------------该指针用来指定线程的属性,若为NULL则线程为默认属性。
void *(*start_routine) (void )---------指向一个返回值是void的函数指针,函数入口参数为void *型;该函数是线程运行函数;
void *arg-------------------线程函数运行时需要传入的参数。

线程的退出

void pthread_exit(void *retval);

参数介绍:
void *retval:线程调用函数退出时,向进程传递的信息,可以是结构体。
进程中的其他线程(包括进程本身)可以调用pthread_join()来访问这个指针。
线程的等待

int pthread_join(pthread_t thread, void **retval);

返回值:成功返回0,失败返回错误编号。
thread:为创建线程时指定的线程ID号。
void **retval:一个二级指针,来接收线程返回时传递的信息。

下面代码是简单的创建一个线程

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>



void *fun1(void *par)
{
    while(1)
    {
        printf("t1: ID = %ld \n",pthread_self());   //pthread_self();获取当前线程的ID号
        sleep(1);
    }
    pthread_exit(NULL);                             //线程退出可以返回值,这里写NULL,不返回
}


int main(int argc, char **argv)
{
    int ret;
    pthread_t t1;       //创建线程标识符

    ret = pthread_create(&t1,NULL,fun1,NULL); //创建线程,返回值为0代表创建成功
    if(ret == 0)
    {
        printf("pthread t1 success \n");
    }

    pthread_join(t1,NULL);      //等待某个线程退出,第二个参数可以获取返回值,暂且不获取。写NULL,如果不等待线程退出,当main函数结束时,线程随之结束。


    return 0;
}

程序执行结果:

在这里插入图片描述

在执行线程的时候要在main函数里面等待线程退出,否则当main函数控制线程退出后,线程也会随之退出。
pthread_join(t1,NULL);
该函数等待线程t1退出,并且不获取线程t1的参数。

线程的互斥锁

互斥所的作用:

我们开启多个线程时,线程的资源是共享的,多个线程同时跑起来时,会交叉的运行,具体谁先运行,谁后运行看linux内核的调度。
当我们想要一个线程执行完后再去执行另外一个线程时,我们就需要对线程进行“加锁”和“解锁”。对线程加锁之后,其他想要访问这个线程里面的资源时,需要等到加锁线程解锁后才能访问。

下面是一个线程的加锁和解锁:

void *fun1(void *par)
{
    pthread_mutex_lock(&mutex);
    printf("t1 : this is pthread one par=%d\n",*((int*)par));
    printf("t1 : this is t1 g_data = %d\n",g_data++);
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

加锁之后线程会执行完两个printf函数进行解锁,加锁之后,会保证锁里面的内容执行完后再执行其他的,但是“加锁”和“解锁”的操作不能保证哪个线程先运行。

互斥锁的初始化

int pthread_mutex_init(pthread_mutex_t *restrict mutex,
           const pthread_mutexattr_t *restrict attr);

我们在使用互斥锁时要先对互斥锁进行初始化。
参数介绍:
pthread_mutex_t *restrict mutex
互斥锁变量用 pthread_mutex_t 类型进行定义。
const pthread_mutexattr_t *restrict attr
锁的属性设置,一般写NULL要具体用的时候可以看一下参数介绍。

互斥锁的销毁

int pthread_mutex_destroy(pthread_mutex_t *mutex);

参数介绍:
pthread_mutex_t *mutex
销毁哪一把锁。

加锁和解锁

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

我们看没有加锁的情况

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>


int g_data = 0;
//pthread_mutex_t  mutex;
void *fun1(void *par)
{
    int i = 0;
//    pthread_mutex_lock(&mutex);
    while(1)
    {
        i++;
        if(i==3)
        {
            break;
        }
        printf("t1 : this is pthread one par=%d\n",*((int*)par));
        sleep(1);
        printf("t1 : this is t1 g_data = %d\n",g_data++);
    }
//    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

void *fun2(void *par)
{
    int i = 0;
//    pthread_mutex_lock(&mutex);
    while(1)
    {
        i++;
        if(i==3)
        {
            break;
        }
        printf("t2 : this is pthread two par=%d\n",*((int*)par));
        sleep(1);
        printf("t2 : this is t1 g_data = %d \n",g_data++);
    }
//    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    int ret;
    pthread_t t1;
    pthread_t t2;
    int param = 100;
//    pthread_mutex_init(&mutex,NULL);

    ret = pthread_create(&t1,NULL,fun1,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t1 success \n");
    }

    ret = pthread_create(&t2,NULL,fun2,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t2 success \n");
    }

    printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

//    pthread_mutex_destroy(&mutex);

    return 0;
}

执行结果:
在这里插入图片描述
我们可以看到,没有上锁时,t1和t2线程交叉执行,t1和t2线程在竞争资源。

我们看上了锁之后:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>


int g_data = 0;
pthread_mutex_t  mutex;
void *fun1(void *par)
{
    int i = 0;
    pthread_mutex_lock(&mutex);
    while(1)
    {
        i++;
        if(i==3)
        {
            break;
        }
        printf("t1 : this is pthread one par=%d\n",*((int*)par));
        sleep(1);
        printf("t1 : this is t1 g_data = %d\n",g_data++);
    }
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

void *fun2(void *par)
{
    int i = 0;
    pthread_mutex_lock(&mutex);
    while(1)
    {
        i++;
        if(i==3)
        {
            break;
        }
        printf("t2 : this is pthread two par=%d\n",*((int*)par));
        sleep(1);
        printf("t2 : this is t1 g_data = %d \n",g_data++);
    }
    pthread_mutex_unlock(&mutex);
    pthread_exit(NULL);
}

int main(int argc, char **argv)
{
    int ret;
    pthread_t t1;
    pthread_t t2;
    int param = 100;
    pthread_mutex_init(&mutex,NULL);

    ret = pthread_create(&t1,NULL,fun1,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t1 success \n");
    }

    ret = pthread_create(&t2,NULL,fun2,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t2 success \n");
    }

    printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
    pthread_join(t1,NULL);
    pthread_join(t2,NULL);

    pthread_mutex_destroy(&mutex);

    return 0;
}

执行结果:
在这里插入图片描述
当一个线程里面解锁之后别的线程回去竞争这个锁,竞争到锁的线程进行上锁,等到解锁之后别的线程才能竞争。

线程的条件变量

条件变量的作用
条件变量用来跟互斥量一起使用,在一个线程里面可以触发一个信号,另外一个线程等待触发线程的信号后执行当前线程。

//条件变量的创建
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
//条件变量的销毁
int pthread_cond_destroy(pthread_cond_t cond);
//等待
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
//多了一个等待时间参数*restrict timeout
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, cond struct timespec *restrict timeout);
//信号触发
int pthread_cond_signal(pthread_cond_t cond);
//信号广播
int pthread_cond_broadcast(pthread_cond_t cond);

线程条件变量的创建

int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);

参数介绍:
pthread_cond_t *restrict cond
条件变量pthread_cond_t 定义
const pthread_condattr_t *restrict attr
除非需要创建一个非默认属性的条件变量,否则pthread_cont_init函数的attr参数可以设置为NULL。

线程条件变量的销毁

int pthread_cond_destroy(pthread_cond_t cond);

参数介绍:
pthread_cond_t cond
需要销毁的条件变量

信号的触发

//信号触发
int pthread_cond_signal(pthread_cond_t cond);

经常与int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);函数一起使用。
当一个线程信号触发时,另一个线程等到这个触发信号时当前线程开始执行。

我们来看函数的简单使用:

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>


int g_data = 0;
pthread_mutex_t  mutex;  //定义一个锁
pthread_cond_t cond = PTHREAD_COND_INITIALIZER; //静态初始化条件变量cond

void *fun1(void *par)
{
    static int cont = 0;
    //  static int ret = 10;
    static char* str = "hello word";
    while(1)
    {
        pthread_cond_wait(&cond,&mutex);
        printf("t1 : this is t1 g_data = %d\n",g_data);
        g_data = 0;
        cont++;
        if(cont == 5)
        {
            exit(0);
        }
    }
    pthread_exit((void*)str);       //线程退出返回值
}

void *fun2(void *par)
{
    //  static int ret = 10;
    printf("%d \n",*((int *)par));
    static char* str = "nice baby";
    while(1)
    {
        printf("t2 : this is t1 g_data = %d \n",g_data++);
        if(g_data == 3)
        {
            pthread_cond_signal(&cond); //发送信号
        }
        sleep(1);

    }
    pthread_exit((void*)str);
}

int main(int argc, char **argv)
{
    int ret;
    pthread_t t1;
    pthread_t t2;
    int param = 100;
    char *prr = NULL;
    pthread_mutex_init(&mutex,NULL);

    ret = pthread_create(&t1,NULL,fun1,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t1 success \n");
    }

    ret = pthread_create(&t2,NULL,fun2,(void*)&param); //创建线程

    if(ret == 0)
    {
        printf("pthread t2 success \n");
    }

    printf("this is main thread id =%ld \n",(unsigned long)pthread_self());
    pthread_join(t1,(void**)&prr);
    pthread_join(t2,(void**)&prr);

    pthread_cond_destroy(&cond);
    pthread_mutex_destroy(&mutex);

    return 0;
}

线程2的变量g_data加到3时,触发信号,线程1等到信号触发是时执行程序。
执行结果如下:

pthread t1 success 
pthread t2 success 
this is main thread id =140428182296384 
100 
t2 : this is t1 g_data = 0 
t2 : this is t1 g_data = 1 
t2 : this is t1 g_data = 2 
t1 : this is t1 g_data = 3
t2 : this is t1 g_data = 0 
t2 : this is t1 g_data = 1 
t2 : this is t1 g_data = 2 
t1 : this is t1 g_data = 3
知识有待提高!
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值