1.多线程的概念
每个进程都有自己的数据段、代码段和堆栈段,这就造成进程在创建、切换、撤销操作时候,需要较大的系统开销。
为了减少系统开销,从进程中演化出来线程。
线程存在于进程中,共享进程的资源。
线程是进程中的独立控制流,由环境(包括寄存器组和程序计数器)和一系列的指令组成,每个进程有一个地址空间和一个控制线程(主线程)。
其实我觉得,进程相当于一个生产工厂,工厂里面的流水线相当于线程,因为进程不共享很多资源,就相当于新建厂房,每个厂房有自己的物料管理,而线程相当于一个工厂里面的流水线,所以可以共享一个同一个工厂里面的物料。
线程A栈 |
线程B栈 |
堆区 |
BSS区 |
数据区 |
代码区 |
进程
2.线程创立pthread_create
每个进程都有对应的进程,是一个非负的整数,数据类型为pid_t ,而线程也有对应的线程号,数据类型为pthread_t (这个不一定是整形,在有些操作系统里面,使用结构体表示,有些系统当成整形数据类型来处理),线程号在系统中不是唯一的,线程号只在他所属的进程环境中有效,线程只在他所处的那个进程里面,线程号才是唯一的。
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
功能:创建一个线程
参数:thread:线程标识符
attr:线程属性结构体的地址,一般用默认属性,传一个NULL
start_routine;线程函数的入口地址,这个地方利用的就是C语言的函数指针
arg:传给线程函数的参数
返回值:成功返回0 ,失败返回非0.
与fork不同的是,pthtrad_create 创建的线程不与父线程在同一点执行,而是从指定的函数开始运行,该函数运行完,该线程就退出了。(意思是父子进程都是在fork之后开始执行),线程是依赖于进程 的,进程结束,线程也就结束了,并且线程函数 的程序在pthread库中,所以链接时候加上参数 -lpthred
示例代码:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
void * thread_func1(void * args )
{
while( 1)
{
printf("pthread1 \n ");
sleep( 1);
}
}
void * thread_func2(void *args )
{
while( 1)
{
printf("pthread2 \n ");
sleep( 1);
}
}
int main(int argc,char *argv[])
{
pthread_t tid1,tid2;
int ret = 0;
ret = pthread_create(&tid1,NULL,thread_func1,NULL );
if( ret !=0)
{
perror( "pthread_cretae 1 error \n ");
return -1;
}
ret = pthread_create(&tid2,NULL,thread_func2,NULL );
if( ret !=0)
{
perror( "pthread_cretae 2 error \n ");
return -1;
}
while(1); // 这个地方加while(1)死循环,是保证进程不死,这样的话,就可以去执行我们创建的哪两个线程,如果不加,进程死亡,那么我们创建的那两个线程也不会执行的。
return 0;
}
2.多线程传参
多线程传参,是通过指针,args的参数类型为void * ,所以可以接收任意的数据类型的指针,但是在线程函数里面使用传过来的参数的时候,需要进行强制类型转换。
譬如:创建线程的时候ret = pthread_create(&tid1,NULL,thread_func1,"helo world" ); 这个“hello world"就会作为参数传给线程函数。
线程函数就可以使用传过来的这个参数:
void * thread_func1(void * args )
{
printf("%s \n",(char *)args);
while( 1)
{
printf("pthread1 \n ");
sleep( 1);
}
}