在说线程资源共享之前,我们先来说来说一下线程的概念,线程就是是进程内部的一条执行序列(即执行流),一个进程至少有一个线程,即main函数代表的执行流。当然我们也可以通过线程库来创建新的线程,这种线程我们称之为函数线程,同一个进程中的所有的线程是并发运行的。而这些线程的一些资源是共享的,今天我们讨论一下文件描述符和数据空间的共享。
我们先来说一下文件描述符,大家先来看下面一段代码:
#include<unistd.h>
#include<stdio.h>
#include<pthread.h>
#include<assert.h>
#include<fcntl.h>
void * fun(void *arg)
{
sleep(1);
int fd=(int)arg;
char ar[128]={0};
int n=read(fd,ar,6);
printf("%s\n",ar);
return NULL;
}
int main()
{
int fd=open("a.txt",O_RDONLY);
assert(fd!=-1);
pthread_t id;
int res=pthread_create(&id,NULL,fun,(void*)fd);
assert(res==0);
int i=0;
for(;i<2;i++)
{
char buff[128]={0};
int n=read(fd,buff,3);
printf("%s\n",buff);
sleep(2);
}
close(fd);
pthread_exit(NULL);
}
我们先来看代码,代码很简单在main线程里我们主要是读取文件中三个长度的内容,在函数线程里我们选择读取六个长度的内容,我们利用sleep()函数控制线程读取文件的顺序,先打印三个字符睡眠的两秒过程中另一个线程并发运行打印六个字符,之后在打印三个字符。
这是a.txt里的内容
这是代码的运行结果:
通过程序运行结果我们可以发现,在读取过程中,我们通过创建函数线程时传递的参数实现了文件的描述符的共享并且根据打印出的数据结合我们学过的文件数据读取机制我们可以发现两个线程之间确实对于文件描述符是共享的。
接下来我们将代码做一点小小的变动:
#include<unistd.h>
#include<stdio.h>
#include<pthread.h>
#include<assert.h>
#include<fcntl.h>
void * fun(void *arg)
{
sleep(1);
int fd=(int)arg;
char ar[128]={0};
int n=read(fd,ar,6);
printf("%s\n",ar);
return NULL;
}
int main()
{
int fd=open("a.txt",O_RDONLY);
assert(fd!=-1);
pthread_t id;
int res=pthread_create(&id,NULL,fun,(void*)fd);
assert(res==0);
int i=0;
for(;i<2;i++)
{
char buff[128]={0};
int n=read(fd,buff,3);
printf("%s\n",buff);
}
sleep(3);
close(fd);
pthread_exit(NULL);
}
a.txt里的内容不变,改变代码之后的程序运行结果如下:
结合文件读取机制这样的结果我们可以发现文件描述符确实共享。
接下来我们再来看一下数据空间的共享,首先我们来说堆区空间的共享。
大家看下面一段代码:
#include<unistd.h>
#include<stdio.h>
#include<pthread.h>
#include<assert.h>
#include<stdlib.h>
void *fun (void *arg)
{
int *ar=(int*)arg;
sleep(1);
int i=0;
for(;i<3;i++)
{
printf("fun runnig\n");
printf("%d\n",ar[i]);
sleep(1);
}
pthread_exit(NULL);
}
int main()
{
printf("main running\n");
int *ar=(int *)malloc(sizeof(int)*3);
int i=0;
pthread_t id;
pthread_create(&id,NULL,fun,ar);
for(;i<3;++i)
{
ar[i]=i;
}
pthread_join(id,NULL);
pthread_exit(NULL);
}
我们在堆区开辟一块数据空间,对其数据进行写入,然后在创建函数线程时将开辟的数组的空间的地址传入,在函数线程内部实现对堆区数据的读取,代码运行结果如下:
我们可以看到,函数进程准确无误的访问到了我们的堆区数据并且将它输出,也可与证明我们线程之间的堆区数据确实是共享的。
接下来我们做的事情是对上面的代码进行细小的改动,将在堆区的申请空间改为在栈区申请一部分空间存储数据,改动如下:
我们将上述代码中的int *ar=(int *)malloc(sizeof(int)*3);改为int ar[3]={0};其余不做改变,重新编译运行后我们得到的结果与之前一样,运行结果依旧没有改变,可以说明栈区空间数据依然共享。
数组如此,我们的单个变量也是如此,但是要注意单个变量在值传递过程中要注意我们的pthraed_create()函数的 最后一个参数类型是void *,因此我们进行值传递的过程中要注意类型的转换以及我们的void*类型是四字节大小,因此大于四字节的数据类型的值是无法传递的。