「Linux 线程的共享内存使用」 (linux 线程 共享内存)

Linux 线程的共享内存使用

随着计算机技术的不断发展,多线程编程已经成为了我们日常开发中的一个常见的技术。在多线程编程中,线程之间的数据的共享和通信也成为了关键的问题。而共享内存就是解决线程之间数据共享和通信的一种方式。

Linux 内核为多进程和多线程提供了一种共享内存的机制,使各个进程和线程之间可以共享一片内存区域,从而实现数据的共享和传递。在 Linux 中,共享内存可以通过系统调用 shmget() 和 shmat() 来实现。shmat() 调用将共享内存附加到调用进程的地址空间中,而 shmget() 则负责分配共享内存区域。

在使用 Linux 线程时,共享内存的使用也是非常常见的。线程之间共享内存,可以提高程序的运行效率,并且可以使多个线程协同工作,完成更加复杂的任务。下面来介绍一下 Linux 线程的共享内存使用。

需要实现线程之间的共享内存,需要开辟一块共享内存区域。这个共享内存区域可以通过 shmget() 系统调用来实现。shmget() 调用需要指定共享内存的大小、权限以及共享内存的标识符等参数。例如,下面的代码演示了如何使用 shmget() 来创建一个共享内存区域。

“`

#include

#include

#include

#include

#define SHMSZ 27

int mn()

{

int shmid;

key_t key;

char* shm, s;

key = 5678;

if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666))

{

perror(“shmget”);

exit(1);

}

if ((shm = shmat(shmid, NULL, 0)) == (char*)-1)

{

perror(“shmat”);

exit(1);

}

for (s = ‘a’; s

{

*shm++ = s;

}

*shm = 0;

return 0;

}

“`

上述代码通过调用 shmget() 创建一个共享内存区域,并且在程序中向共享内存区写入了一个小写字母表。在使用共享内存的过程中,需要注意内存的大小以及内存的权限问题。共享内存的权限可以使用 chmod() 系统调用来设置,并且需要保证各个线程对共享内存的访问权限相同。

接下来,在 Linux 线程中使用共享内存,需要使用 shmat() 系统调用将共享内存附加到线程的地址空间中。下面的代码演示了在 Linux 线程中使用共享内存。

“`

#include

#include

#include

#include

#include

#define SHMSZ 27

void* thread_func(void* arg)

{

char* shm = (char*)arg;

while (*shm != 0)

{

putchar(*shm++);

}

putchar(‘\n’);

return NULL;

}

int mn()

{

int shmid;

key_t key;

char* shm;

pthread_t thread;

key = 5678;

if ((shmid = shmget(key, SHMSZ, 0666))

{

perror(“shmget”);

exit(1);

}

if ((shm = shmat(shmid, NULL, 0)) == (char*)-1)

{

perror(“shmat”);

exit(1);

}

pthread_create(&thread, NULL, thread_func, (void*)shm);

pthread_join(thread, NULL);

return 0;

}

“`

上述代码创建了一个 Linux 线程,并且将共享内存附加到线程的地址空间中。线程使用了共享内存来获取数据并打印输出。在使用共享内存的过程中,需要注意几个问题:首先需要保证共享内存是按照约定的方式进行使用,否则可能会引起不可预见的错误;其次需要注意内存空间的大小,以及内存的读写操作的互斥问题;需要避免共享内存的数据出现竞争的情况,从而保证数据的正确性和安全性。

相关问题拓展阅读:

  • Linux C++多线程同步的四种方式
  • 麻烦解释一下linux下进程和线程有什么区别和联系,linux下多线程和多进程通信的实现方法,请通俗解释

Linux C++多线程同步的四种方式

From :

1.同一个线程内部,指令按照先后顺序执行;但不同线程之间的指令很难说清楚是哪一个先执行,在并况下,指令执行的先后顺序由内核决定。

如果运行的结果依赖于不同线程执行的先后的话,那么就会形成竞争条件,在这样的情况下,计算的结果很难预知,所以应该尽量避免竞争条件的形成。

2.最常见的解决竞争条件的方法是:将原先分离的两个指令构成一个不可分割的原子操作,而其他任务不能插入到原子操作中!

3.对

多线程

来说,同步指的是在一定时间内只允许某一个线程访问某个资源,而在此时间内,不允许其他线程访问该资源!

互斥锁

条件变量

读写锁

信号量

一种特殊的

全局变量

,拥有lock和unlock两种状态。

unlock的互斥锁可以由某个线程获得,一旦获得,这个互斥锁会锁上变成lock状态,此后只有该线程由权力打开该锁,其他线程想要获得互斥锁,必须得到互斥锁再次被打开之后。

1.互斥锁的初始化, 分为静态初始化和动态初始化.

2.互斥锁的相关属性及分类

(1) attr表示互斥锁的属性;

(2) pshared表示互斥锁的共享属性,由两种取值:

1)PTHREAD_PROCESS_PRIVATE:锁只能用于一个进程内部的两个线程进行互斥(默认情况)

2)PTHREAD_PROCESS_SHARED:锁可用于两个不同进程中的线程进行互斥,使用时还需要在进程共享内存中分配互斥锁,然后为该互斥锁指定属性就可以了。

互斥锁存在缺点:

(1)某个线程正在等待共享数据内某个条件出现。

(2)重复对数据对象加锁和解锁(轮询),但是这样轮询非常耗费时间和资源,而且效率非常低,所以互斥锁不太适合这种情况。

当线程在等待满足某些条件时,使线程进入睡眠状态;一旦条件满足,就换线因等待满足特定条件而睡眠的线程。

程序的效率无疑会大大提高。

1)创建

静态方式:pthread_cond_t cond PTHREAD_COND_INITIALIZER

动态方式:int pthread_cond_init(&cond,NULL)

Linux thread 实现的条件变量不支持属性,所以NULL(cond_attr参数)

2)注销

int pthread_cond_destory(&cond)

只有没有线程在该条件变量上,该条件变量才能注饥亩销,否则返回EBUSY

因为Linux实现的条件变量没有分配什么资源,所以注销动作只包括检查是否姿肢改有等待线程!(请参考条件变量的底层实现)

3)等待

条件等待:int pthread_cond_wait(&cond,&mutex)

计时等待:int pthread_cond_timewait(&cond,&mutex,time)

1.其中计时等待如果在给定时刻前条件没有被满足,则返回ETIMEOUT,结束等待

2.无论那种等待方式,都必须有一个互斥锁配合,以防止多个线程同时请求pthread_cond_wait形成竞争条件!

3.在调用pthread_cond_wait前必须由本线程加锁

4)激发

激发一个等待线程:pthread_cond_signal(&cond)

激发所有等待线程:pthread_cond_broadcast(&cond)

重要的是,pthread_cond_signal不会存在惊群效应,也就是是它最多给一个等待线程发信号,不会给所有线程发信号唤醒,然后要求他们自己去争抢资源!

pthread_cond_broadcast() 唤醒所有正在pthread_cond_wait()的同一个条件变量的线程。注意:如果等待的多个现场不使用同一个锁,被唤迹判醒的多个线程执行是并发的。

pthread_cond_broadcast & pthread_cond_signal

1.读写锁比互斥锁更加具有适用性和并行性

2.读写锁最适用于对

数据结构

的读操作读操作次数多余写操作次数的场合!

3.锁处于读模式时可以线程共享,而锁处于写模式时只能独占,所以读写锁又叫做共享-独占锁。

4.读写锁有两种策略:强读同步和强写同步

强读同步:

总是给读者更高的优先权,只要写者没有进行写操作,读者就可以获得访问权限

强写同步:

总是给写者更高的优先权,读者只能等到所有正在等待或者执行的写者完成后才能进行读

1)初始化的销毁读写锁

静态初始化:pthread_rwlock_t rwlock=PTHREAD_RWLOCK_INITIALIZER

动态初始化:int pthread_rwlock_init(rwlock,NULL),NULL代表读写锁采用默认属性

销毁读写锁:int pthread_rwlock_destory(rwlock)

在释放某个读写锁的资源之前,需要先通过pthread_rwlock_destory函数对读写锁进行清理。释放由pthread_rwlock_init函数分配的资源

如果你想要读写锁使用非默认属性,则attr不能为NULL,得给attr赋值

int pthread_rwlockattr_init(attr),给attr初始化

int pthread_rwlockattr_destory(attr),销毁attr

2)以写的方式获取锁,以读的方式获取锁,释放读写锁

int pthread_rwlock_rdlock(rwlock),以读的方式获取锁

int pthread_rwlock_wrlock(rwlock),以写的方式获取锁

int pthread_rwlock_unlock(rwlock),释放锁

上面两个获取锁的方式都是阻塞的函数,也就是说获取不到锁的话,调用线程不是立即返回,而是阻塞执行,在需要进行写操作的时候,这种阻塞式获取锁的方式是非常不好的,你想一下,我需要进行写操作,不但没有获取到锁,我还一直在这里等待,大大拖累效率

所以我们应该采用非阻塞的方式获取锁:

int pthread_rwlock_tryrdlock(rwlock)

int pthread_rwlock_trywrlock(rwlock)

互斥锁只允许一个线程进入临界区,而信号量允许多个线程进入临界区。

1)信号量初始化

int sem_init(&sem,pshared, v)

pshared为0,表示这个信号量是当前进程的局部信号量。

pshared为1,表示这个信号量可以在多个进程之间共享。

v为信号量的初始值。

返回值

成功:0,失败:-1

2)信号量值的加减

int sem_wait(&sem):以原子操作的方式将信号量的值减去1

int sem_post(&sem):以原子操作的方式将信号量的值加上1

3)对信号量进行清理

int sem_destory(&sem)

麻烦解释一下linux下进程和线程有什么区别和联系,linux下多线程和多进程通信的实现方法,请通俗解释

区别和联系:

1、进程是独立运行的实体,有独立的资源分配;

2、同一进程的线程之间共享进程的资源;

3、所有的进程至洞皮少有一个执行线程;

4、纳仔差线程的创建和切换代价比进程的小;

线程间的通信方法:

1、同一进程的线程之间通信戚喊的最简单办法就是使用全局变量;

2、不同进程的线程之间通信需要通过下面进程间的通信来实现;

进程间的通信方法:

1、管道

2、信号量

3、共享内存

4、消息队列

5、套接字

兄弟看到你这么高的分我就找了些资料:也算是对昨天学的知识总结一下吧

一、先说概念不管是windows还是linux下的进程和线程概念都是一样的,只是管理进程和线程的方式不一样,这个是前提,到时候你可别问我windows下进程和线程啊。这个涉及到操作系统原理。下面给你解答。

说道进程不得不提作业这个名词 ,我想兄弟你电脑里不会有一个程序吧对不?当你的系统启动完毕后你看看你的任务管理器里是不是有很多进程呢?那么多程序是怎么调如内存呢?能理解吗?这里要明白程序和进程的关系,程序是你磁盘上的一个文件,当你需要它时进入内存后才成为进程,好比QQ在磁盘上就是一个文件而已,只有进入了内存才成为进程,进程神首搜是活动的。QQ要扫描你文件啊,记录你聊天记录啊,偷偷上传个啥东西什么的你也不知道对不,他是活动的。这个能明白吗?

再看作业,这个作业可不是你写作业的那个作业啊。系统一看好家伙你个QQ那么大的家伙你想一下子进入内存啊?没门!慢慢来嘛,系统就把QQ程序分为好几块,这几块不能乱分的,要符合自然结构就是循环啦选择啦这样的结构,你把人家循环结构咔嚓截断了,怎么让人家QQ运行啊?这就是作业要一块一块的进入内存,同时要为作业产生JCB(JOB CONTROL BLOCK)作业控制块,你进入内存不能乱跑啊,要听系统的话,你要是进入系统自己的内存。框一下,内存芹悉不能读写 对话框就出来了,严重点直接蓝脸给你!你懂得。这是window下的,linux下直接给你报错!没事了就!所一系统通过jcb控制进程。JCB包含了进程号优先级好多内容,你打开你的windows任务管理器看看进程是不是有好多属性啊?那就是PCB(PRCESS,CONTROL BLOCK)同理作业也包含那些内容只是多少而已。下面写出进程特点:

、进程是分配计算机资源最小的单位。你想啊人是要用程序干活的吧?你把程序调入内存成了就成了进程,所以说进程是分配资源的最小单位。你在linux下打开终端输入top命令看是不是有好多进程?

2、进程有操作系统为作业产生。有“父进程”产生“子进程”之间是父子关系,并可以继续向下产生“子进程”。还拿QQ来说,你双击QQ.exe。QQ启动了输入账号密码打开主界面了。这时候你要聊天,QQ进程赶紧产生个“儿子”说 “儿子你去陪主人聊天去吧。这样子进程产生了。突然你想看美女要传照片这时候那个”儿子“有”生“了一个”儿子“说”儿子“你去传照片。那个“儿子领到任务去传照片了。这时你想关了QQ,QQ提示你说”你还有个“儿子”和“孙子”还在干活呢你真要结束吗?你蒽了确定。QQ对他“儿子”(你聊天窗口)说:”儿子啊对不起了,主人要关闭我你也不能活啊“咔嚓一下”儿子“死了,儿子死之前对他儿子说:“儿子啊你爷爷不让我活了,你也别活了咔嚓孙子也死了。最后世界安静了。这就是进程的父子关系。能明白吗?记住:进程之活动在内存中。不能使用CPU,只管分配资源。

再说线程:线程也产生在内存中并且在内存中存在相当长的时间,但它的活动区域主要在CPU中,并且运行和灭亡都存在于CPU中,可以这么说,线程是程序中能被系统调度进入CPU中最小程序单位,它能直接使用进程分配的CPU的资源。

还拿QQ来说当你要传文件时QQ总要判断一下文件的扩展名吧,ok这时那个”儿子“赶紧对它爸爸说我需要一个线程判断扩展名QQ赶紧对一个管这个的线程说:”快点去CPU里计算下那个扩展名是什么然后向主人报告计算完了就“死了”消亡了,但是它的线程还在内存中!还等着你下一次传文件然后计算然后消亡!

线程之间是相互独立的。一个在CPU,一个在内存里还能有关系吗对不?CPU在每一个瞬间只能进入一个线程,当线程进入CPU时立即产生一个新的线程,新线程仍停留在内存中,就好比上面那个传文件还会等着你再传文件再计算扩展名。

线程相对线程是独立的,但它在内存中并不是独立的,这就好比你不开QQ能用QQ传输文件吗?它只存在与进程分配的资源中,也就是说计算扩展名这个线程只能停留在QQ这个进程中,不能跑到别的进程里!!相当于程序产生了新的进程游历和线程,进程向CPU申请资源,再有线程来使用,他们都是为程序服务的只是分工不同!

因为你没提问linux下是怎么管理进程和线程的所以我就不回答了,这个问题我建议你还是看看《笨兔兔的故事》里面讲到了linux是怎么管理进程和线程的。挺幽默的比我说得还好。

你第二个问题说实话我回答不了你!我想你现在连进程和线程还没理解第二个你更理解不了了你说对不?我猜的其实你用C/C++不管是在windows下编程还是在Linux下编程思想都是一样的对吧,如果你理解了在windows下线程间通信,在linux更没问题了!

参考资料:黑客手册2023合订本非安全之一二季244页,245页,328页,329页,398页,399页

浅谈操作系统原理 (一 二三)

ubuntu中文论坛 笨兔兔的故事

希望我的回答你能理解

这玩意还真通俗不了,区别还是很多的,而且每条都能说上大半天。。。可以先说下联系。首先Linux包括内核线程、进程、用户线程这三个概念,内核线程是在linux内核中的概念,进程通常是都是用户空间中的概念,但是由于在内核中为用户空间创建进程的时候,和创建内核线程是基本一样的,所以可以说或者可以看成一个进程对应一个内核线程,但还有内核线程不是用于服务进程的。而用户线程不是内核的概念,换句话说用户线程对于内核来说一无所知,所以从这个角度说进程和用户线程一点关系都没有。由于线程通常是由线程库提供的,例如posix线程库、cthread线程库等,这些线程库是用户空间动态链接库,所以哪个进程调用这个库,线程以及线程管理、调度程序就在哪个进程里,不同进程调用的库所带来的线程、线程管理都相互无关。这就是联系了。现在说区别,讨论区别要分类看,首先是调度:进程调度由内核来调度,进程在内核里有内核线程来支持,一个内核线程自然包含一套数据结构来存储相关信息;用户线程是库文件支持的,所以数据结构定义、调度函数都在库里,当然为了提高用户线程的被调度的权限以及实时性等优势,有的线程库已经通过一些方式让内核知道用户线程的存在,这是更远的话题了行轿兄。再看内存:最常说的一句话就是进程有独立的内存空间而线程没有,含义是每个进程有自己的一套页表,一套页表就意味着一个完整的内存空间,比如32位操作系统里就是2G或者3G的空间(视不同的CPU和操作系统内核实现方式),由于进程在内核里有自己的地位,所以更换进程就能更换整个页表;线程在内核里没有地位,所以只要进程没换,线程换档袭了,页表还是没变,所以大家的空间一样,这个时候只能靠程序员自己去保护各个线程以及线程库的能力,举个例子:我变了一个程序a.exe和另一个程序b.exe,让b的源码里有个函数叫abc(),在a的源码里我不可能帆岁直接调用abc(),因为编译完了,即使我告诉编译器abc()函数在b.exe里的地址给a源码,在运行时a.exe进程空间里的那个地址放的绝对不是b里的abc()函数,这时只能使用远程调用,一个远程调用的过程基本上和一次网络上两个机子传递一次数据包差不多,可见对于操作系统来说a和b进程里的东西与两台机子上的东西一样,相互隔离相互独立。这两类区别还会引申出很多细节上的区别,但都归根于这两点。希望对你有帮助

什么是Linux线程?

专业点的说法,线程被定义为一个独立的指令流,它本身的运转由操作系统来安蠢让银排,但是,这意味着什么呢?对软件开发者来说,解释线程更好的描述就是”procedure”可以独立于主程序运行。再进一步,设想一个包含了大量procedure的主程序,然后想象所有这些procedure在操作系统的安排下一起或者独立的运行,这就是对于多线程程序的一个简单描述。问题是,它是如何实现的呢?在弄懂线程之前,之一步要搞清楚Unix进程。进程作系统创建,并需带宴要相当多的”开支”,进程包含如下程序资源和程序执行状态信息:进程ID,进程群组ID,用户ID,群组ID环境工作目录程序指令寄存器栈堆文件描述符信号动作共享库进程间通信工具(例如消息队列,管道,信号量,共享内存)

Unix进程Unix进程内部的线程

线程使用和在进程内的生存,仍由操作系统来安排并且独立的实体来运行,很大程度上是因为它们为可执行代码的存在复制了刚刚好的基本资源。这个独立的控制流之所以可以实现,是因为线程维护着如下的东西:栈指针寄存器调度属性(例如规则和优先级)等待序列和阻塞信号线程拥有的数据

所以,总的来说,Unix环境里的线程有如下特点:它生存在进程中,并使用进程资源;拥有它自己独立的控制流,前提是只要它的父进程还存在,并且OS支持它;它仅仅复制可以使它自己调度的必要的资源;它可能会同其它与之同等独立的线程分享进程资源;如果父进程死掉那么它也会死掉–或者类似的事情;它是轻量级的,因为大部分的开支已经在它的进程创建时完成了。因为在同一进程内的线程分享资源,所以:一个线程对共享的系统资源做出的改变(例如关闭一个文件)会被所有的其它线滑嫌程看到;指向同一地址的两个指针的数据是相同的;对同一块内存进行读写操作是可行的,但需要程序员作明确的同步处理操作.

程序的一次执行叫一个进程,每个进程有独立的堆栈段、代码段、数据段。而且进程是系统进行资源分配和调度的最小单位,多进程之间是拥有独立的内存单元的。

线程是进程的一个实体,是CPU调度和分派的基本单位,可以和隶属与同一个进程的其它线程共享进程所拥有的全部资源。同一个进程中的多个线程可以并发执行,多线程之间拥有共享的内存单元,迅配悉这样以提高执行效率。

这样说吧,一个程序至少包含一个进程,一个进程至少包含一个线程。

进程的创建:fork()

线程的创建:pthread_create()

进程间通信主要是管道、卖镇消息队列、信号量等等,搜缩关键字IPC一大把,这里就不说了。

同一进程的线程间通信主要是全局亩乎变量,上面说了,这些线程之间拥有共享的内存单元嘛,也就是共享的数据段。

而不同进程的线程间的通信,主要是借助了进程间通信的机制实现了啊

linux 线程 共享内存的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于linux 线程 共享内存,「Linux 线程的共享内存使用」,Linux C++多线程同步的四种方式,麻烦解释一下linux下进程和线程有什么区别和联系,linux下多线程和多进程通信的实现方法,请通俗解释的信息别忘了在本站进行查找喔。

版权声明:本文采用知识共享 署名4.0国际许可协议 [BY-NC-SA] 进行授权
文章名称:《「Linux 线程的共享内存使用」 (linux 线程 共享内存)》
文章链接:https://zhuji.vsping.com/28093.html
本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。