Linux - 多线程

No.1 线程基础

一、什么是线程:

1. 进程是os资源分配的基本单位 : 资源
2. 线程是os调度的基本单位 : 代码
3. windows跟linux多线程类似,但是函数名不同,方式不同。
  • 区别:
    1. 一个进程里面可以有多个线程,同一个进程中的多个线程共享进程资源
  • 本质上进程和线程的没有区别
    1. 2.2版本的linux内核中,没有线程,只有进程,并且进程数量有限,共4096个
    2. 2.4版本开始,内核中有了线程的概念,线程个数无线
  • 线程和进程都是进程的结构体

二、如何创建线程:

一个进程种至少存在一个进程	主进程	main函数
pthread_create函数 创建并立刻启动线程

	#include <pthread.h>
    int pthread_create(
    	   	pthread_t *thread, 				//线程id 作为返回值来使用
        	const pthread_attr_t *attr,		//线程属性
      	void *(*start_routine) (void *),//线程函数 是一个函数指针
      	void *arg);						//线程函数的参数

    Compile and link with -pthread. 
    由于函数声明在pthread.h中,但是函数定义在pthread这个动态库中,因此编译的时候需要链接这个库

关于linux上的编译以及动态库的介绍点击这里

  • 函数指针: 函数名就是函数的地址
    对于第三个参数,如果没有将函数指针强转为要求的类型,会报错,但是可以运行。gcc pthread.c -l pthread编译的时候需要带上库
  • C与C++的区别:
    • C不做强制类型检查,
    • C++做强制类型检查
      pthread.c
#include <stdio.h>
#include <pthread.h> 
#include <unistd.h>     //sleep


//void *(*start_routine) (void *)
//两种解决方案
//一、将函数定义为符合它的要求的函数 void*()(void*)
//二、强制类型转换
typedef void* (*A)(void*);//给线程函数指针类型取别名 A
//A指针类型是一个符合要求的指针类型


//原void f1()
//一、void* f1(void* a)
void f1()
{
    for(int i=0;i<10;i++)
    {
        printf("子线程:%d\n",i);
        sleep(1);
    }
    printf("分支线程结束\n");

}

int main()
{
    int n = 0;
    //pid可以直接为NULL,也可定义一个pthread_t的变量
    pthread_t pid;
    pthread_create(&pid,NULL,(A)f1,NULL);
    for(int i=0;i<10;i++)
    {
        printf("主线程:%d\n",i);
        sleep(1);
    }
    for(int i=0;i<5;i++)
    {
        printf("主线程再来一会:%d\n",i);
        sleep(1);
    }
    printf("主线程结束\n");
    return 0;
}

三、线程的结束:

	1. 自然返回
			+ 线程函数返回
	2. 主线程要结束了
		 	+ 主线程会结束所有的分支线程
	3. 自己结束自己
			+ pthread_exit
			+ `void pthread_exit(void *retval);`
	4. 被其他线程干掉
			+ pthread_cancel
			+  `int pthread_cancel(pthread_t thread);`
				thread 就是创建时的第一个参数

四、线程的参数和返回值

  1. 参数
    多个参数可以创建一个结构体,然后将结构体实例化后传地址放在线程创建的第四个参数位置。在线程函数中强转传入的地址就可以正常使用了。
struct Student
{
	char name[20];
	int age;
	double score;
};
void* f(void* p)
{
	struct Student* ps = (struct Student*)p;
	//然后就可以对ps正常使用
}
int main()
{
	struct Student s={"张三",13,33.33};
	pthread_create(NULL,NULL,f,&s);

}
  1. 返回值
    主线程结束前,会结束所有的分支线程。
    等待某个线程结束:
    + wait
    + pthread_jion

     int pthread_join(
     		pthread_t thread,
     		void **retval);		//获取返回值
     
     void* 就是int,所以它不仅可以接受单个的返回值,也可以像传结构体那样接受结构体,即多个返回值不过在函数返回时需要传地址。
    

    五、什么时候使用多线程:需要并发的时候

    • 并发又叫并行,它跟串行是反面。
    • 串行是单任务,并发是多任务。
    • 并不是并发一定会比串行快,如果计算任务超过了cpu的计算,那么有对对不同线程的调度也需要消耗时间,因此相对来说还会比串行效率慢。

六、临界数据

  • 同一个进程内的多个线程共享进程的资源,那么必定会造成资源的征用
  • 多个线程同时访问同一块内存段,会造成临界数据、脏的问题

七、线程同步:解决临界数据脏的问题

应用层:
	原子锁
	自旋锁
	信号量 	前面的文章里有
内核态:
	读写锁
	互斥量
	临界变量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值