Linux 多线程编程( POSIX )( 六 )----->代码区 ( 共享内存实例 )
2012-03-21 06:48
447 查看
注意:以下编译加上 -lrt
例如:gcc -o server server.c -lrt
1.创建一个共享内存区的例子
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
int main( int argc, char ** argv )
{
intshm_id;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_CREAT | O_RDWR, 0644 ) ) <= 0)
{ //!> 创建共享区
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
printf("共享区ID == %d \n", shm_id );
shm_unlink(argv[1] ); //!> 删除共享区
return0;
}
2.使用mmap映射将一个文件中内容cp到一个新建的文件
注意:必须有一个现有的 old 文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
int main( int argc, char ** argv )
{
int fd_in,fd_out; //!> 源文件和新建的文件 文件描述符
void *src; //!> 源
void *des; //!> 目的
struct statstat_buf; //!> 文件信息结构体
if( argc !=3 ) //!> 注意参数:2个文件名
{
printf("请输入两个文件名!\n");
exit(EXIT_FAILURE );
}
if( ( fd_in= open( argv[1], O_RDONLY ) ) < 0) //!> 打开源文件
{ //!>
只读打开
perror(argv[1] );
}
if( ( fd_out= open( argv[2], O_RDWR|O_CREAT|O_TRUNC ) ) < 0)
{ //!>
创建新文件
perror(argv[2] ); //!> 若文件存在,则长度被截为0,属性不变
}
if( fstat(fd_in, &stat_buf ) < 0) //!> 获取源文件信息
{
printf("获取源文件信息失败" );
exit(EXIT_FAILURE );
}
if( lseek(fd_out, stat_buf.st_size - 1, SEEK_SET ) == -1 )
{ //!> 初始化输出映射存储区
printf("lseek Error...\n");
exit(EXIT_FAILURE );
}
if( write(fd_out, "1", sizeof( "1" )) == -1 )
{
printf("写入错误!\n");
exit(EXIT_FAILURE );
}
if( ( src =mmap( 0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd_in, 0 ) ) ==MAP_FAILED )
{
printf("源文件映射错误。。。");
exit(EXIT_FAILURE );
}
if( ( des =mmap( 0, stat_buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,fd_out, 0 ) ) == MAP_FAILED )
{
printf("目标文件映射错误。。。\n");
exit(EXIT_FAILURE );
}
memcpy( des,src, stat_buf.st_size); //!> 复制
munmap( src,stat_buf.st_size); //!> 删除映射关系
munmap( des,stat_buf.st_size );
close( fd_in);
close(fd_out );
return0;
}
3.显示共享区信息
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
int main( int argc, char ** argv )
{
int shm_id =-1;
struct statbuf;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1 )
{ //!>
创建共享区
printf("创建共享区失败....\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0) //!> 修改共享区大小
{
printf("修改共享区大小失败...\n");
exit(EXIT_FAILURE );
}
if( fstat(shm_id, &buf ) != 0) //!> 获取文件(共享区)信息
{
printf("获取共享区信息失败...\n");
exit(EXIT_FAILURE );
}
printf("uid_t: %d\n", buf.st_uid); //!> 共享内存区所有者ID
printf("git_t: %d\n", buf.st_gid); //!> 共享内存区所有者组ID
printf("size: %d\n", ( int )buf.st_size); //!> 共享内存区大小
return0;
}
4.共享内存区的写入和读出
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
int main( int argc, char ** argv )
{
int shm_id =-1;
char* ptr =NULL;
struct stat buf;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_CREAT | O_RDWR, 0644 ) ) == -1 )
{ //!> 创建共享区
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0) //!> 修改共享区大小
{
printf("修改共享区失败...\n" );
exit(EXIT_FAILURE );
}
if( fstat(shm_id, &buf ) != 0 )
{
printf("获取共享区信息失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, buf.st_size, PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0 )) == MAP_FAILED )
{
printf("创建映射失败....\n");
exit(EXIT_FAILURE );
}
//!> 注意,此后的ptr就是共享区首地址咯!
strcpy( ptr,"Hello Linux memory map ..."); //!> 写入
printf("输入共享区内容:%s\n", ptr);
shm_unlink(argv[1] ); //!> 删除映射
return0;
}
5.C-S模式实例
//!> cs.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>
//!> server.c
#include "cs.h"
int main( int argc, char ** argv )
{
int shm_id =-1;
sem_t* sem;
char * ptr;
if( argc !=2 )
{
printf("请输入共享区名称!\n" );
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1 )
{
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0 )
{
printf("修改内存区大小失败...\n");
exit(EXIT_FAILURE );
}
if( ( sem =sem_open( argv[1], O_CREAT, 0644, 1 ) ) == SEM_FAILED )
{ //!> 注意此处创建的信号量在内核运行段都有效,只要不销毁
printf("创建互斥信号量失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0 ) )== MAP_FAILED )
{
printf("创建映射失败...\n");
exit(EXIT_FAILURE);
}
strcpy( ptr,"\0" );
//!> 我们分析可以知道:ptr是和共享区连到一起,那么此处其实
//!> 就是接收client传过来的请求字符串,所以只要不是NULL和
//!> q退出字符,那么就输出而已... ...
while( 1)
{
if( (strcmp( ptr, "\0" ) ) == 0) //!> 内容为空则等待
{
continue;
}
else
{
if( (strcmp( ptr, "q\n" ) ) == 0) //!> q + 回车退出
{
break;
}
sem_wait(sem ); //!> 申请信号量
printf("server: %s \n", ptr);
strcpy( ptr,"\0" );
sem_post(sem ); //!> 释放信号量
}
sem_unlink(argv[1] ); //!> 删除信号量
shm_unlink(argv[1] ); //!> 删除共享区
}
return0;
}
//!> client.c
#include "cs.h"
int main( int argc, char ** argv )
{
int shm_id =-1;
char* ptr;
sem_t* sem;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open(argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1) //!> 打开共享区
{
printf("打开共享区失败...\n");
exit(EXIT_FAILURE );
}
if( ( sem =sem_open( argv[1], 0 ) ) == SEM_FAILED) //!> 打开信号量
{
printf("打开信号量失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0 ) )== MAP_FAILED) //!> 链接到共享区
{
printf("连接映射失败...\n");
exit(EXIT_FAILURE);
}
while( 1)
{
sem_wait(sem ); //!> 申请信号量
printf("客户请求->");
fgets( ptr,10, stdin ); //!> 从键盘读入
printf("client: %s\n", ptr);
if( strcmp(ptr, "q\n" ) == 0) //!> 退出
{
exit(EXIT_SUCCESS );
}
sem_post(sem ); //!> 释放
sleep( 1);
}
return0;
}
结果:
客户请求->aaa
client:aaa
server:aaa
客户请求->bbb
client:bbb
server:bbb
客户请求->q
client:q
例如:gcc -o server server.c -lrt
1.创建一个共享内存区的例子
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
int main( int argc, char ** argv )
{
intshm_id;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_CREAT | O_RDWR, 0644 ) ) <= 0)
{ //!> 创建共享区
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
printf("共享区ID == %d \n", shm_id );
shm_unlink(argv[1] ); //!> 删除共享区
return0;
}
2.使用mmap映射将一个文件中内容cp到一个新建的文件
注意:必须有一个现有的 old 文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
int main( int argc, char ** argv )
{
int fd_in,fd_out; //!> 源文件和新建的文件 文件描述符
void *src; //!> 源
void *des; //!> 目的
struct statstat_buf; //!> 文件信息结构体
if( argc !=3 ) //!> 注意参数:2个文件名
{
printf("请输入两个文件名!\n");
exit(EXIT_FAILURE );
}
if( ( fd_in= open( argv[1], O_RDONLY ) ) < 0) //!> 打开源文件
{ //!>
只读打开
perror(argv[1] );
}
if( ( fd_out= open( argv[2], O_RDWR|O_CREAT|O_TRUNC ) ) < 0)
{ //!>
创建新文件
perror(argv[2] ); //!> 若文件存在,则长度被截为0,属性不变
}
if( fstat(fd_in, &stat_buf ) < 0) //!> 获取源文件信息
{
printf("获取源文件信息失败" );
exit(EXIT_FAILURE );
}
if( lseek(fd_out, stat_buf.st_size - 1, SEEK_SET ) == -1 )
{ //!> 初始化输出映射存储区
printf("lseek Error...\n");
exit(EXIT_FAILURE );
}
if( write(fd_out, "1", sizeof( "1" )) == -1 )
{
printf("写入错误!\n");
exit(EXIT_FAILURE );
}
if( ( src =mmap( 0, stat_buf.st_size, PROT_READ, MAP_SHARED, fd_in, 0 ) ) ==MAP_FAILED )
{
printf("源文件映射错误。。。");
exit(EXIT_FAILURE );
}
if( ( des =mmap( 0, stat_buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED,fd_out, 0 ) ) == MAP_FAILED )
{
printf("目标文件映射错误。。。\n");
exit(EXIT_FAILURE );
}
memcpy( des,src, stat_buf.st_size); //!> 复制
munmap( src,stat_buf.st_size); //!> 删除映射关系
munmap( des,stat_buf.st_size );
close( fd_in);
close(fd_out );
return0;
}
3.显示共享区信息
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
int main( int argc, char ** argv )
{
int shm_id =-1;
struct statbuf;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1 )
{ //!>
创建共享区
printf("创建共享区失败....\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0) //!> 修改共享区大小
{
printf("修改共享区大小失败...\n");
exit(EXIT_FAILURE );
}
if( fstat(shm_id, &buf ) != 0) //!> 获取文件(共享区)信息
{
printf("获取共享区信息失败...\n");
exit(EXIT_FAILURE );
}
printf("uid_t: %d\n", buf.st_uid); //!> 共享内存区所有者ID
printf("git_t: %d\n", buf.st_gid); //!> 共享内存区所有者组ID
printf("size: %d\n", ( int )buf.st_size); //!> 共享内存区大小
return0;
}
4.共享内存区的写入和读出
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <fcntl.h>
int main( int argc, char ** argv )
{
int shm_id =-1;
char* ptr =NULL;
struct stat buf;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_CREAT | O_RDWR, 0644 ) ) == -1 )
{ //!> 创建共享区
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0) //!> 修改共享区大小
{
printf("修改共享区失败...\n" );
exit(EXIT_FAILURE );
}
if( fstat(shm_id, &buf ) != 0 )
{
printf("获取共享区信息失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, buf.st_size, PROT_READ|PROT_WRITE,MAP_SHARED,shm_id,0 )) == MAP_FAILED )
{
printf("创建映射失败....\n");
exit(EXIT_FAILURE );
}
//!> 注意,此后的ptr就是共享区首地址咯!
strcpy( ptr,"Hello Linux memory map ..."); //!> 写入
printf("输入共享区内容:%s\n", ptr);
shm_unlink(argv[1] ); //!> 删除映射
return0;
}
5.C-S模式实例
//!> cs.h
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <semaphore.h>
//!> server.c
#include "cs.h"
int main( int argc, char ** argv )
{
int shm_id =-1;
sem_t* sem;
char * ptr;
if( argc !=2 )
{
printf("请输入共享区名称!\n" );
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open( argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1 )
{
printf("创建共享区失败...\n");
exit(EXIT_FAILURE );
}
if(ftruncate( shm_id, 100 ) != 0 )
{
printf("修改内存区大小失败...\n");
exit(EXIT_FAILURE );
}
if( ( sem =sem_open( argv[1], O_CREAT, 0644, 1 ) ) == SEM_FAILED )
{ //!> 注意此处创建的信号量在内核运行段都有效,只要不销毁
printf("创建互斥信号量失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0 ) )== MAP_FAILED )
{
printf("创建映射失败...\n");
exit(EXIT_FAILURE);
}
strcpy( ptr,"\0" );
//!> 我们分析可以知道:ptr是和共享区连到一起,那么此处其实
//!> 就是接收client传过来的请求字符串,所以只要不是NULL和
//!> q退出字符,那么就输出而已... ...
while( 1)
{
if( (strcmp( ptr, "\0" ) ) == 0) //!> 内容为空则等待
{
continue;
}
else
{
if( (strcmp( ptr, "q\n" ) ) == 0) //!> q + 回车退出
{
break;
}
sem_wait(sem ); //!> 申请信号量
printf("server: %s \n", ptr);
strcpy( ptr,"\0" );
sem_post(sem ); //!> 释放信号量
}
sem_unlink(argv[1] ); //!> 删除信号量
shm_unlink(argv[1] ); //!> 删除共享区
}
return0;
}
//!> client.c
#include "cs.h"
int main( int argc, char ** argv )
{
int shm_id =-1;
char* ptr;
sem_t* sem;
if( argc !=2 )
{
printf("请输入共享区名称!\n");
exit(EXIT_FAILURE );
}
if( ( shm_id= shm_open(argv[1], O_RDWR | O_CREAT, 0644 ) ) == -1) //!> 打开共享区
{
printf("打开共享区失败...\n");
exit(EXIT_FAILURE );
}
if( ( sem =sem_open( argv[1], 0 ) ) == SEM_FAILED) //!> 打开信号量
{
printf("打开信号量失败...\n");
exit(EXIT_FAILURE );
}
if( ( ptr =mmap( NULL, 100, PROT_READ | PROT_WRITE, MAP_SHARED, shm_id, 0 ) )== MAP_FAILED) //!> 链接到共享区
{
printf("连接映射失败...\n");
exit(EXIT_FAILURE);
}
while( 1)
{
sem_wait(sem ); //!> 申请信号量
printf("客户请求->");
fgets( ptr,10, stdin ); //!> 从键盘读入
printf("client: %s\n", ptr);
if( strcmp(ptr, "q\n" ) == 0) //!> 退出
{
exit(EXIT_SUCCESS );
}
sem_post(sem ); //!> 释放
sleep( 1);
}
return0;
}
结果:
客户请求->aaa
client:aaa
server:aaa
客户请求->bbb
client:bbb
server:bbb
客户请求->q
client:q
相关文章推荐
- Linux 多线程编程( POSIX )( 四 )------>代码区 ( 互斥量实例 )
- Linux 多线程编程( POSIX )( 五 )----->代码区 ( 条件变量实例 )
- Linux 多线程编程( POSIX )( 三 )------->代码区 ( 信号灯实例 )
- Linux 多线程编程( POSIX )( 二 )----->代码区 ( pthread_attr_t 线程属性实例 )
- Linux 多线程编程( POSIX )( 六 )----->共享内存区
- Linux 多线程编程( POSIX )( 六 )----->共享内存区
- Linux 多线程编程( POSIX )( 一 ) ----> 代码区
- Linux 多线程编程( POSIX )( 二 )----->代码区
- Linux 多线程编程( POSIX )( 一 ) ----> 代码区
- Linux 多线程编程( POSIX )( 三 )------->代码区
- Linux 多线程编程( POSIX )( 二 )----->pthread_attr_t 线程属性
- Linux 多线程编程( POSIX )( 二 )----->pthread_attr_t 线程属性
- Linux 多线程编程( POSIX )( 五 )----->条件变量
- Linux 多线程编程( POSIX )( 四 )------>互斥量
- Linux 多线程编程( POSIX )( 五 )----->条件变量
- Linux 多线程编程( POSIX )( 一 )-----> 基础篇
- Linux 多线程编程( POSIX )( 二 )----->pthread_attr_t 线程属性
- Linux 多线程编程( POSIX )( 一 )-----> 基础篇
- Linux 多线程编程( POSIX )( 三 )------->信号灯
- Linux 多线程编程( POSIX )( 三 )------->信号灯