【Linux】实验报告5 进程和线程同步

【封面】Linux实验报告
作者|Ricky的水果摊

时间|2022年6月30日


文章目录

实验目的

加深对进程概念的理解,认识并发执行的实质,分析进程征用资源的现象, 学习进程、线程互斥的方法。

实验原理

1.线程的基本概念

  • 线程是一条执行路径,是计算机中 独立运行的最小单位,它是进程的一个执行流,是 CPU调度和分派的基本单位

  • 一个进程可以由多个线程组成,线程间 共享进程的所有资源,但每个线程又有各自的堆栈和局部变量

    • 对于单核CPU而言:多线程就是一个CPU在来回的切换,在交替执行。
    • 对于多核CPU而言:多线程就是同时有多条执行路径在同时(并行)执行,每个核执行一个线程,多个核就有可能是一块同时执行的。
  • 一个正在运行的软件(如百度网盘)就是一个进程,一个进程可以同时运行多个任务( 百度网盘可以同时下载多个文件,每个下载任务就是一个线程),可以简单的认为进程是线程的集合。

线程介绍的相关博客—CSDN

2.进程与线程的关系

一个操作系统中可以有多个进程,一个进程中可以包含一个线程(单线程程序),也可以包含多个线程(多线程程序)

image-20220607174254432

线程相对于进程的优点

  • 在一个程序中需要并发处理多个任务时(例如需要并发监控2个不同的fifo),以多线程的方式编程更符合人的思维
  • 多线程编程使得多个任务间的 通信更加直观和方便(例如可以使用共享的全局变量)
  • 多线程的 切换开销 更小

3.线程的相关函数

3.1 pthread_self()
pthread_self()功能

获取当前线程的ID,类似于用 getpid()获取当前进程PID

pthread_self()原型
#include <pthread.h>

pthread_t pthread_self(void);
pthread_self()返回值

返回当前线程的ID

pthread_self()参数解释

该函数无传入参数

pthread_self()编程实例
pthread_t tid          //可以理解为 typedef unsigned long int pthread_t
tid = pthread_self();  //获取当前线程ID
printf("Current thread's ID is %lu\n", tid);
3.2 pthread_create()
pthread_create()功能

创建一个新的线程,类似于用 fork()创建子进程

pthread_create()原型
#include <pthread.h>

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

如果操作成功,返回0;如果操作失败,返回错误值

pthread_create()参数解释

pthread_t *thread 表示新创建的线程ID 指向的内存单元

const pthread_attr_t *attr 表示线程属性,通常为 NULL

void *(*start_routine) (void *) 函数指针,新创建的线程将从start_routine函数的地址开始运行

void *arg 若start_routine函数需要参数,将参数放入结构中并将地址作为arg传入,通常为NULL

pthread_create()编程实例
void * thread1(void *arg){         //定义thread1函数指针,作为start_routine
        pthread_t thid=pthread_self();
        printf("Current thread's ID is %lu\n", thid);
}

int main(){
	pthread_t tid;   

	if( (tid = pthread_create(&tid,NULL,thread1,NULL) != 0){  //创建一个新的进程
  	perror("thread create failed");
  	exit(1);
	}
     
}
3.3 pthread_exit()
pthread_exit()功能

结束当前线程

pthread_exit()原型
#include <pthread.h>

void pthread_exit(void *retval);
pthread_exit()返回值

该函数无返回值

pthread_exit()参数解释

void *retval 表示线程退出状态,通常为NULL

pthread_exit()编程实例
void * thread1(void *arg){      
  			pthread_exit(NULL);   //退出当前线程
}
exit() & pthread_exit()
  • 在任何线程里使用 exit(),都会导致进程终止,使得 其他线程还未完成当前任务,就被终止

  • 因此,在多线程环境中,应 **少用或不使用 exit(),而是用 pthread_exit(),将单个线程

3.4 pthread_join()
pthread_join()功能

阻塞主线程,获取子线程退出状态,类似于用 waitpid()阻塞父进程并且获得子进程退出状态

pthread_join()原型
#include <pthread.h>

int pthread_join(pthread_t thread, void **retval);
pthread_join()返回值

如果操作成功,返回0;如果操作失败,返回错误值

pthread_join()参数解释

pthread_t thread 表示想要获取退出状态的子线程的ID

void **retval 表示指向 指定线程的退出码的 二级指针 (类似于 wait(&status)中的 &status )

pthread_join()编程实例
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

void* thread_run(void* arg)
{
        sleep(3);
        printf("thread %lu is running\n",pthread_self());
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, NULL, thread_run,NULL);

    pthread_join(tid,NULL);  //主线程"main"会阻塞,直到tid线程执行完毕
    printf("main thread exit\n");
    return 0;
}

image-20220606160741318

4. 多线程同步的概念

  • 线程最大的特点是资源的共享性,然而多个线程同时访问某个资源时(如全局变量),如果这些线程的读写操作发生冲突,就会导致该资源的状态出现混乱
  • Linux系统提供了多种方式处理线程间的同步问题,其中最常用的有 互斥锁条件变量异步信号

5. 互斥锁的相关函数

互斥锁通过锁机制来实现线程的同步。在同一时刻它通常只允许一个线程执行关键部分的代码

5.1 pthread_mutex_init()
pthread_mutex_init()功能

初始化指定的互斥锁

pthread_mutex_init()原型
//动态初始化
int pthread_mutex_init(pthread_mutex_t *mutex,const pthread_mutexattr_t *mutexattr);

//静态初始化
pthread_mutex_t mutex = PTHREAD_MUTEXT_INITIALIZER;
pthread_mutex_init()返回值

如果操作成功,返回0;如果操作失败,返回错误值

pthread_mutex_init()参数解释

pthread_mutex_t *mutex 表示指定的互斥锁的地址

const pthread_mutexattr_t *mutexattr 表示互斥量属性,通常为NULL

pthread_mutex_init()编程实例
pthread_mutex_t mutex;   //创建一个互斥锁mutex

pthread_mutex_init(&mutex,NULL)  //动态初始化该互斥锁
动态初始化 VS 静态初始化

动态初始化 在堆中创建,不用时需要删除以释放内存
静态初始化 在静态存储区,初始化之后直接使用,不用时也不需要删除

5.2 pthread_mutex_lock()
pthread_mutex_lock()功能

若指定的互斥锁处于开锁状态,则锁上该锁;若处于上锁状态,则阻塞线程,直至该锁被打开,再上锁

pthread_mutex_lock()原型
int pthread_mutex_lock(pthread_mutex_t *mutex);
pthread_mutex_lock()返回值

如果操作成功,返回0;如果操作失败,返回错误值

pthread_mutex_lock()参数解释

pthread_mutex_t *mutex 表示指定的互斥锁的地址

pthread_mutex_lock()编程实例
if (pthread_mutex_lock(&mutex) != 0);   //将mutex互斥锁给锁上
	perror("lock mutex failed\n")
5.3 pthread_mutex_unlock()
pthread_mutex_unlock()功能

若指定的互斥锁处于上锁状态,则打开该锁

pthread_mutex_unlock()原型
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_unlock()返回值

如果操作成功,返回0;如果操作失败,返回错误值

pthread_mutex_unlock()参数解释

pthread_mutex_t *mutex 表示指定的互斥锁的地址

pthread_mutex_unlock()编程实例
if (pthread_mutex_unlock(&mutex) != 0);   //将mutex互斥锁给打开
	perror("unlock mutex failed\n")
5.4 pthread_mutex_destroy()
pthread_mutex_destroy()功能

销毁指定的互斥锁

pthread_mutex_destroy()原型
int pthread_mutex_destroy(pthread_mutex_t *mutex)
pthread_mutex_destroy()返回值

如果操作成功,返回0;如果操作失败,返回错误值

pthread_mutex_destroy()参数解释

pthread_mutex_t *mutex 表示指定的互斥锁的地址

pthread_mutex_destroy()编程实例
pthread_mutex_destroy(&mutex)  //动态初始化该互斥锁

6. 条件变量的相关函数

  • 条件变量是利用线程间共享的全局变量进行同步的一种机制。

  • 条件变量宏观上类似if语句,符合条件就能执行某段程序,否则只能等待条件成立。

  • 条件变量不是一把锁,它实质上一个类似信号的东西,与锁相互配合使用,因为锁所能达到的功能就只有加锁和解锁,并不能实现线程之间的一些关联,于是条件变量就出现了,与锁相互配合使用。这与共享内存与信号量配合使用有些许相似之处。

条件变量相关函数介绍

实验作业

createthread.c实践

源代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
int * thread(void * arg) {
   
        pthread_t newthid;
        newthid = pthread_self()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值