Linux多线程(线程、互斥锁、条件变量)

零基础小白学习Linux系统编程对线程的了解。对于引用了线程的程序的编译需要加 -lpthread

一、 进程与线程

进程:资源(CPU,内存等)分配的最小单位,是线程的容器;它有独立的地址空间,所以一般情况下不会影响其他进程。进程切换时,耗费资源较大,效率差。

线程:程序执行的最小单位,是进程的不同执行路径;它有自己的堆栈和局部变量,但没有单独的地址空间,所以一个线程死掉就等于整个进程死掉。

与多进程相比多线程更加“节俭”,线程间的通信更加方便。

二、线程常用API

对于线程:
pthread_create——线程创建
pthread_exit——线程退出
pthread_join——线程等待

对于互斥锁:
pthread_mutex_init——创建互斥锁
pthread_mutex_destroy——销毁互斥锁
pthread_mutex_lock——加锁
pthread_mutex_unlock——解锁

对于条件变量:
pthread_cond_init——创建条件变量
pthread_cond_destroy——销毁条件变量
pthread_cond_wait——等待
pthread_cond_signal——触发

三、 线程

1、创建线程

//包含头文件
#include <pthread.h>

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

参数含义
1、thread——其指向的内存单元被设置为新创建线程的ID。简单点说就是线程名称(自我理解)。
2、attr——线程属性,默认为NULL。
3、 (*start_routine) (void *)——函数指针,新创建的线程从该函数的地址开始运行,如果要传递的参数不止一个,则需要定义结构体,将结构体地址作为arg传入。

返回值:若成功返回0,否则返回错误编号

2、线程退出

//包含头文件
#include <pthread.h>
   
//函数
void pthread_exit(void *retval);

参数说明: retval是一个指针,可以通过线程等待函数pthread_join来访问该指针。

3、线程等待

#include <pthread.h>

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

参数说明:
1、 thread为需要等待的线程。
2、 retval 用以接收被等待线程传回的值,不需要接收则可设置为NULL。

4、线程ID的获取与比较

#include <pthread.h>

pthread_t pthread_self(void);
//返回值为调用线程的ID

int pthread_equal(pthread_t tid1, pthread_t tid2);

5、代码示例:

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

void* fun1(void* arg)
{
        static int ret=10;

        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("t1:date is %d\n",*((int *)arg));
        pthread_exit((void*)&ret);
}

int main()
{
        int ret;
        int date=50;
        pthread_t t1;
        int *pret;

        ret=pthread_create(&t1,NULL,fun1,(void*)&date);
        if(ret==0){
    		printf("main: create t1 success\n");
        }

        printf("main:ID=%ld\n",(unsigned long)pthread_self());

        pthread_join(t1,(void **)&pret);
        //对于此程序,若没有该等待,一般情况下t1线程还来不及执行主线程就退出了
        printf("main:t1 quit,ret=%d\n",*pret);
        return 0;
}

运行结果:
在这里插入图片描述

四、互斥锁

互斥量(mutex)是加锁与解锁所包含的内容,其本身就相当于一把锁。如果运行到某个线程时,为了让该线程的所有内容不间断执行完(可能会被其他没上锁的线程打断),我们就需要用到互斥锁。如果某个线程加锁后还没走到解锁步骤,任何其他想进行再次加锁的线程都会被阻塞。

1、互斥锁的创建与销毁

//头文件包含
#include <pthread.h>
//创建锁
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *restrict_attr);
//销毁锁
int pthread_mutex_destroy(pthread_mutex_t *mutex)

参数含义:
mutex 锁的名称。
restrict_attr 锁的属性,默认为NULL。

2、加锁和解锁

//头文件包含
#include <pthread.h>
//加锁
int pthread_mutex_lock(pthread_mutex_t mutex);
//解锁
int pthread_mutex_unlock(pthread_mutex_t mutex);

3、代码示例:

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

pthread_mutex_t mutex;

void* fun1(void* arg)
{
        pthread_mutex_lock(&mutex);
        printf("t1:%ld thread is create\n",(unsigned long)pthread_self());
        printf("t1:date is %d\n",*((int *)arg));
        pthread_mutex_unlock(&mutex);
}

void* fun2(void* arg)
{
        int i;
        pthread_mutex_lock(&mutex);
        for(i=0;i<3;i++){
        	printf("t2:%ld thread is create\n",(unsigned long)pthread_self());
        	printf("t2:date is %d\n",*((int *)arg));
            leep(1);
        }
        pthread_mutex_unlock(&mutex);
}

void* fun3(void* arg)
{
        pthread_mutex_lock(&mutex);
        printf("t3:%ld thread is create\n",(unsigned long)pthread_self());
        printf("t3:date is %d\n",*((int *)arg));
        pthread_mutex_unlock(&mutex);
}

int main()
{
        int ret;
        int date=50;
        pthread_t t1;
        pthread_t t2;
        pthread_t t3;

        pthread_mutex_init(&mutex,NULL);
        ret=pthread_create(&t1,NULL,fun1,(void*)&date);
        if(ret==0){
                printf("main: create t1 success\n");
        }

        ret=pthread_create(&t2,NULL,fun2,(void*)&date);
        if(ret==0){
                printf("main: create t2 success\n");
        }

        ret=pthread_create(&t3,NULL,fun3,(void*)&date);
        if(ret==0){
                printf("main: create t3 success\n");
        }

        printf("main:ID=%ld\n",(unsigned long)pthread_self());
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);

        pthread_mutex_destroy(&mutex);
        return 0;
}

运行结果
在这里插入图片描述

五、条件变量

用于线程间相互控制。

1、创建与销毁条件变量

//头文件包含
#include <pthread.h>
//函数
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *restrict);
int pthread_cond_destroy(pthread_cond_t *cond);

参数说明:
cond——条件变量名。
restrict——属性,默认为NULL。

2.、等待与触发

//头文件包含
#include <pthread.h>
//等待:让线程阻塞
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
//触发:触发正在等待的线程
int pthread_cond_signal(pthread_cond_t *cond);//向一个线程发信息
int pthread_cond_broadcast(pthread_cond_t *cond); //向多个线程发信息

参数说明:
cond——环境变量名
mutex——锁名

3、代码示例:满足线程t2的触发条件,线程t1才执行。

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

int p_date=0;
pthread_mutex_t mutex;
pthread_cond_t cond;

void* fun1(void* arg)
{
        static int cnt=0;
        while(1){
        		//一进来处于阻塞状态
                pthread_cond_wait(&cond,&mutex);
                printf("t1 run--------------------------------\n");
                printf("t1:%d\n",p_date);
                p_date=0;
                sleep(1);
                if(cnt++==10){
                        exit(1);
                }
        }
}

void* fun2(void* arg)
{
        while(1){
				printf("t2:%d\n",p_date);
                pthread_mutex_lock(&mutex);
                p_date++;
                if(p_date==3){
                        pthread_cond_signal(&cond);
                }
                pthread_mutex_unlock(&mutex);
                sleep(1);
        }
}

int main()
{
        int ret;
        int date=50;
        pthread_t t1;
        pthread_t t2;

        pthread_mutex_init(&mutex,NULL);
        pthread_cond_init(&cond,NULL);
        ret=pthread_create(&t1,NULL,fun1,(void*)&date);
        ret=pthread_create(&t2,NULL,fun2,(void*)&date);

        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_mutex_destroy(&mutex);
        pthread_cond_destroy(&cond);
        return 0;

运行结果:
在这里插入图片描述
以上内容重复十次。

补充:

对于互斥锁与条件变量的初始化,也可以用静态初始化即使用宏,如:

//头文件包含
#include <pthread.h>

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER
pthread_cond_t cond=PTHREAD_COND_INITIALIZER

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值