进程同步(读写共享内存)



进程同步(读写共享内存)

一、简介

       本文展示了如何使用Win32事件来解决多个读、写线程的同步问题。在编译了源码之后,你会得到作为读、写共享内存而存在的控制台应用程序。同时可以执行多个程序用于测试。但是某一时刻只允许一个程序执行写操作。如果某一个写操作在执行,那么其他读、写程序都会被阻塞。然而,多个读操作可以同时运行。如果读操作正在执行,那么写操作只有在所有读操作完成之后才能处理。这种同步机制确保了读写操作正确同步、避免任意时刻的数据冲突。

二、源码分析

       源码中包含了读写操作使用的共享内存,使用事件机制来实现同步功能。

下面是初始化事件和共享内存的代码:

//初始化事件对象和共享内存对象
bool Initialize()
{
	char szBuffer[32];
	for(int i=0; i<MAX_READ_PROCESSES_ALLOWED; i++)
	{
		sprintf_s(szBuffer, "Reader_%d", i);
		//创建读事件
		g_hReadEvent[i] = CreateEvent(NULL, false, true, szBuffer);
		if(NULL == g_hReadEvent[i])
			return false;
	}

	//创建写事件 
	g_hWriteEvent = CreateEvent(NULL, false, true, g_szWriteName);
	if(NULL == g_hWriteEvent)
		return false;

	//创建共享内存缓冲区
	g_hShareMemory = CreateFileMapping(INVALID_HANDLE_VALUE, 
		NULL, PAGE_READWRITE, 0, MAX_SHARE_MEM_SIZE, g_szShareMemoryName);

	if(NULL==g_hShareMemory || INVALID_HANDLE_VALUE==g_hShareMemory)
	{
		printf("Error occured shile creating file mapping object\n");
		return false;
	}

	g_pBuffer = (LPTSTR)MapViewOfFile(g_hShareMemory, FILE_MAP_ALL_ACCESS, 0, 0, MAX_SHARE_MEM_SIZE);
	if(NULL == g_pBuffer)
	{
		printf("Error occured while mapping view of the file\n");
		return false;
	}

	return true;
}

void ReadAndPrint()
{
	printf("从共享内存中读取数据并打印...\n");
	//等待所有的写操作结束,数据已经同步
	bool bContinue = true;
	while(bContinue)
	{
		printf("等待写操作完成...、\n");
		DWORD dwWaitResult = WaitForSingleObject(g_hWriteEvent, INFINITE);
		if(WAIT_OBJECT_0 == dwWaitResult)
		{
			bool bEventFount = false;
			for(int i=0; i<MAX_READ_PROCESSES_ALLOWED; i++)
			{
				DWORD dwWaitResult = WaitForSingleObject(g_hReadEvent, WAIT_TIMEOUT);
				if(WAIT_OBJECT_0 == dwWaitResult)
				{
					bEventFount = true;
					printf("设置写事件...\n");
					SetEvent(g_hWriteEvent);
					//读共享内存
					printf("共享内存中内容是:%s\n", g_pBuffer);
					printf("设置读事件...\n");
					SetEvent(g_hReadEvent[i]);

					bContinue = false;
					break;
				}
				else
				{
					continue;
				}
			}
		}
		else
		{
			printf("等待出错:%d\n", GetLastError());
		}
	}
}

//写函数使用事件来同步
void WriteAndPrint()
{
	printf("写人并输出共享内存数据...\n");
	printf("等待写操作结束...\n");

	if(WAIT_OBJECT_0 == WaitForSingleObject(g_hWriteEvent, INFINITE))
	{
		printf("等待所有读操作结束...\n");
		DWORD dwWaitResult = WaitForMultipleObjects(MAX_READ_PROCESSES_ALLOWED, 
			g_hReadEvent, TRUE, INFINITE);

		if(WAIT_OBJECT_0 == dwWaitResult)
		{
			printf("输入字符串:(不要空格):");
			printf("%s", g_pBuffer);
			printf("共享内存数据:%s", g_pBuffer);
		}
		else
		{
			printf("等待出错:%d", GetLastError());
		}

		printf("设置写事件...\n");
		SetEvent(g_hWriteEvent);
		printf("设置读事件...\n");
		for(int i=0; i<MAX_READ_PROCESSES_ALLOWED; i++)
		{
			SetEvent(g_hReadEvent[i]);
		}
	}
	else
	{
		printf("deng\n");
	}
}

void DdeInitialize()
{
	for(int i=0; i< MAX_READ_PROCESSES_ALLOWED; i++)
	{
		CloseHandle(g_hReadEvent[i]);
	}

	CloseHandle(g_hWriteEvent);
	UnmapViewOfFile(g_pBuffer);
	CloseHandle(g_hShareMemory);
}

int _tmain(int argc, _TCHAR* argv[])
{
	if (Initialize())
     {
          ...
     }
     else
     {
         ...
     }
     
     bool bContinue = true;
     
     while(bContinue)
     {
          DisplayOptions();
          bContinue = RecvAndProcessOption();
     }
     
     DeInitialize();
     
     return 0; //success
}


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在多进程读写共享内存时,我们可以使用信号量来保证进程之间的同步。信号量是一种系统资源,它可以用来控制进程的访问和使用共享资源的次数。 在Linux系统中,使用semget函数创建一个信号量集合,使用semop函数对信号量进行操作。semop函数可以实现信号量的P操作和V操作,P操作将信号量的值减1,V操作将信号量的值加1。 下面是一个简单的使用semop函数实现多进程读写共享内存的示例: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h> #include <sys/shm.h> #define KEY 1234 #define SEM_KEY 4321 int main() { int semid, shmid, *shm; struct sembuf sem_p, sem_v; pid_t pid; // 创建信号量集合 semid = semget(SEM_KEY, 1, IPC_CREAT | 0666); if (semid == -1) { perror("semget error"); exit(1); } // 初始化信号量 if (semctl(semid, 0, SETVAL, 1) == -1) { perror("semctl error"); exit(1); } // 创建共享内存 shmid = shmget(KEY, sizeof(int), IPC_CREAT | 0666); if (shmid == -1) { perror("shmget error"); exit(1); } // 映射共享内存 shm = (int *)shmat(shmid, NULL, 0); if (shm == (int *)-1) { perror("shmat error"); exit(1); } *shm = 0; pid = fork(); if (pid == -1) { perror("fork error"); exit(1); } else if (pid == 0) { // 子进程共享内存 sem_p.sem_num = 0; sem_p.sem_op = -1; sem_p.sem_flg = SEM_UNDO; semop(semid, &sem_p, 1); printf("Child process write %d\n", ++(*shm)); sem_v.sem_num = 0; sem_v.sem_op = 1; sem_v.sem_flg = SEM_UNDO; semop(semid, &sem_v, 1); exit(0); } else { // 父进程共享内存 sem_p.sem_num = 0; sem_p.sem_op = -1; sem_p.sem_flg = SEM_UNDO; semop(semid, &sem_p, 1); printf("Parent process read %d\n", *shm); sem_v.sem_num = 0; sem_v.sem_op = 1; sem_v.sem_flg = SEM_UNDO; semop(semid, &sem_v, 1); wait(NULL); } // 解除共享内存映射 if (shmdt(shm) == -1) { perror("shmdt error"); exit(1); } // 删除共享内存 if (shmctl(shmid, IPC_RMID, 0) == -1) { perror("shmctl error"); exit(1); } // 删除信号量集合 if (semctl(semid, 0, IPC_RMID, 0) == -1) { perror("semctl error"); exit(1); } return 0; } ``` 在上面的示例中,我们创建了一个信号量集合和一个共享内存。父进程共享内存,子进程共享内存,两个进程都使用了信号量来保证同步。 在共享内存之前,子进程使用P操作将信号量的值减1,如果信号量的值为0,则子进程会阻塞等待。当子进程共享内存之后,它使用V操作将信号量的值加1,这样父进程就可以继续共享内存了。 在共享内存之前,父进程也使用P操作将信号量的值减1,如果信号量的值为0,则父进程会阻塞等待。当父进程共享内存之后,它使用V操作将信号量的值加1,这样子进程就可以继续共享内存了。 需要注意的是,使用信号量来保证进程之间的同步时,要确保每个进程都正确地使用P操作和V操作,否则可能会导致死锁或者竞争条件。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值