Linux——进程与线程内存共享

本文探讨了在Linux环境下使用fork创建子进程时遇到的同步问题,并通过具体示例介绍了如何利用信号量解决进程间的资源竞争问题。

一直以来,我都认为在Linux下使用fork创建的新的进程和父进程具有相同的代码段和相同的全局数据段,但是今天遇到了一点问题!!!!

             例程:使用父子进程共同打印一段字符串,子进程打印前半,父进程后半,时间间隔1s,初步源码如下:


#include <stdio.h>
#include <unistd.h>
#include <string.h>

int main()
{
	int i,j;
	pid_t pid;
	const char *message="this is a test string\n";
	int n = strlen(message) / 2;
	pid = fork();
	j = (pid == 0 ? 0 : n);
	for ( i = 0; i < n; i++)
	{
		write(STDOUT_FILENO,message + i + j,1);
		sleep(1);
	}
	return 0;
}
//运行结果混乱。
因为涉及到同步的的问题,所以使用信号量来解决,代码如下:
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

int main()
{
	int i,j;
	pid_t pid;
	const char *message="this is a test string\n";
	int n = strlen(message) / 2;
	
        sem_t sem;
sem_init(&sem,2,0);pid = fork();
j = (pid == 0 ? 0 : n);
if(pid > 0)
{
sem_wait(&sem);
}
for ( i = 0; i < n; i++)
{
write(STDOUT_FILENO,message + i + j,1);
sleep(1);
}
if(pid == 0)
{
sem_post(&sem);
}
sem_destroy(&sem);
return 0;
}
//结果子进程正常打印,父进程一直等待获取信号量的位置。

十分不解,使用gdb调试后发现,在子进程中出现的效果和自己设想的一样(即:sem.__align的值+1),按理说这样后父进程能够获取到信号量才对。。。很明显了,父子进程的地址空间的虚拟地址一样,但是指向的数据区域的实际物理地址不一样。。。。

然后稍微的改了一下程序,将sem_t sem;定义为全局变量,但是结果依旧。。子进程仍然无法改变父进程的地址空间中的值。

然后就将无名信号改成了有名信号:程序如下:

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>

//static sem_t sem;
int main()
{
	int i,j;
	pid_t pid;
	const char *message="this is a test string\n";
	int n = strlen(message) / 2;
	sem_t *sem;
	sem = sem_open("/sem", O_CREAT, S_IRUSR | S_IWUSR, 0);
	pid = fork();
	j = (pid == 0 ? 0 : n);
	if(pid > 0)
	{
		sem_wait(sem);
	}
	for ( i = 0; i < n; i++)
	{
		write(STDOUT_FILENO,message + i + j,1);
		sleep(1);
	}
	if(pid == 0)
	{
		sem_post(sem);
	}
	sem_destroy(sem);
	return 0;
}
//得到了预期结果
然后。。。。突然醒悟。。。。

如果父子进程能够直接共享局部变量和全局变量数据,还用管道、共享内存……干嘛。。。。



                
### 操作系统中进程线程的概念 #### 进程 (Process) 进程是操作系统结构的基础,表示程序的一次执行过程。每个进程都有独立的代码和数据空间(指令、栈、堆),具有分配资源的功能单位。进程由文本区(即代码)、数据区以及用户堆栈组成,并且拥有自己的地址空间[^1]。 ```c // 创建新进程的例子 pid_t pid; pid = fork(); // Unix/Linux创建子进程的方式 if (pid < 0){ printf("error in fork!"); } else if(pid == 0){ printf("I am child process"); } else { wait(NULL); // 父进程等待子进程结束 } ``` #### 线程 (Thread) 线程有时被称为轻量级进程(Lightweight Process),同一进程内的多个线程共享进程中大部分的数据和状态信息,如文件描述符、信号处理设置等;但是它们各自有自己的调用栈(call stack) 和寄存器集合(registers set)[^2]。 ```java class MyThread extends Thread{ public void run(){ System.out.println("This is a thread."); } } public class Main { public static void main(String[] args) { new MyThread().start(); } } ``` ### 进程线程的主要区别 - **定义不同** - 进程是一个具有一定独立功能的程序关于某个数据集上的一次运行活动,而线程则是进程的一个实体,是CPU调度和分派的基本单位[^3]。 - **开销方面** - 启动一个新的进程所需的时间较长,因为这涉及到加载新的环境并初始化所有的上下文。相比之下,启动一个新线程则要快得多,因为它只需要复制父线程的一些属性即可完成创建工作[^4]。 - **资源共享** - 不同进程之间无法直接访问对方的内存区域,如果需要交换数据,则必须通过特定机制实现跨进程通讯(IPC) 。然而,在同一个进程下的各个线程间可以直接读写彼此所在的全局变量或静态方法中的局部变量,因此更容易进行协作工作。 - **通信方式** - 对于多进程而言,通常采用消息队列(message queue), 套接字(socket pair) 或者管道(pipe)等方式来进行相互通信;而对于属于同一进程的不同线程来说,由于它们都处于相同的地址空间内,故可通过共享存储器(shared memory segment)来高效传递信息。 - **调度粒度** - 在现代操作系统里,实际被调度的对象往往是线程而非整个进程——尽管后者确实包含了前者所需的全部资源和支持条件。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值