linux下c语言编程4-使用共享内存实现进程间通信

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

linux下C语言编程4-使用共享内存实现进程间通信
共享内存的函数有以下几个:
(1)int shmget(key_t key, int size, int shmflg),开辟或使用一块共享内存。

(2)void *shmat(int shmid, const void *shmaddr, int shmflg),将参数shmid所指向的共享内存与当前进程连接。

当使用某共享内存时,需要先使用shmat,达成连接。

(3)int shmdt(const void *shmaddr),将先前用shmat连接的共享内存与当前进程解除连接。

参数shmaddr为shmat返回的共享内存的地址。

在完成对共享内存的使用后,需要使用shmdt解除连接。

(4)int shmctl(int shmid, int cmd, struct shmid_ds *buf),控制内存的操作。

当cmd 为IPC_RMID时,删除shmid所指的共享内存。

这些函数的表头文件为<sys/ipc.h>和<sys/shm.h>,其详细参数请去网上搜索。

下面给出一个使用共享内存实现进程间通信的例子:进程A开辟一块新的共享内存,进程B 修改这个共享内存,进程C打印输出这个共享内存的内容,进程D删除这个共享内存。

进程BCD运行的命令格式为:命令共享内存ID,如./output 123432。

进程A代码如下:
int main()
{
int shmid;
shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT | 0600);
if (shmid < 0)
{
perror("shmget error");
exit(1);
}
printf("create shared memory OK. shmid=%d/n", shmid);
return 0;
}
进程B代码如下:
int main(int argc, char *argv[])
{
int shmid;
char *shmaddr;
if (argc != 2)
{
perror("argc error/n");
exit(1);
}
shmid = atoi(argv[1]);
shmaddr = (char *)shmat(shmid, NULL, 0); if ((int )shmaddr == -1)
{
perror("shmat error./n");
exit(1);
}
strcpy(shmaddr, "hello, world!");
shmdt(shmaddr);
return 0;
}
进程C代码如下:
int main(int argc, char *argv[])
{
int shmid;
char *shmaddr;
if (argc != 2)
{
printf("argc error/n");
exit(1);
}
shmid = atoi(argv[1]);
shmaddr = (char *)shmat(shmid, NULL, 0); if ((int )shmaddr == -1)
{
perror("shmat error./n");
exit(1);
}
printf("%s/n", shmaddr);
shmdt(shmaddr);
return 0;
}
进程D代码如下:
int main(int argc, char *argv[])
{
int shmid;
if (argc != 2)
{
perror("argc error/n");
exit(1);
}
shmid = atoi(argv[1]);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}
linux下C语言编程5-多线程编程
Linux系统下的多线程遵循POSIX线程接口,称为pthread。

编写Linux下的多线程程序,需要使用头文件pthread.h,编译需要在后面加-lpthread。

关于多线程,主要有以下几个过程:
1,创建线程
2,各个线程的执行
3,等待线程的结束
涉及的线程函数主要有:
1,int pthread_create(pthread_t *restrict tidp, const pthread_attr_t *restrict attr, void *(*start_rtn)(void), void *restrict arg);
函数有4个参数:第一个参数为指向线程标识符的指针。

第二个参数用来设置线程属性。

第三个参数是一个函数指针(有关函数指针,看这里),指向线程运行函数的起始地址。

最后一个参数是函数指针所需要的参数。

注意:pthread_create函数返回0表示成功。

另外如果函数指针需要多个参数的话,就将
这些参数做成某个结构体,作为第4个参数。

如果有返回值的话,也可将返回值的指针回写到第4个参数中。

2,pthread_join()等待一个线程的结束。

pthread_exit()用于线程退出,可以指定返回值,以便其他线程通过pthread_join()函数获取该线程的返回值。

线程的应用:并行数据库的查询
假设我们有3台计算机A, B, C,每台均安装PG数据库,通过网络连接。

我们可以通过多线程将查询SQL广播出去,A,B,C并行查询,最终返回各自的结果。

如果没有多线程,而只是用了个循环,那么我们获取结果的过程将是顺序的,即等A的结果返回后才能查询B,B结束后查询C,效率低下。

代码如下:
//最多支持MAX个线程 #define MAX 16
/**** 多线程 ******/
typedef struct PDthread
{
char *host; // IP
int port; // 端口
char *dbname; // 数据库名
char *query; // SQL语句
void *rst; // 查询结果
}PDthread;
typedef struct Nodes
{
int count; // 实际上的节点数量count<=MAX
char host[MAX][32];
int port[MAX];
}Nodes; /* 线程的执行过程,参数m为PDthread结构 */
void *PDthreadSelect(void *m)
{
PDthread *p = (PDthread *)m;
p->rst = (void *)ExecuteQuery(p->host, p->port, p->dbname, p->query);
pthread_exit(NULL);
return NULL;
} /* 创建多个线程,1个node对应1个线程 * 输出:thread[], pdthread * 输入:node, dbname, query, 这些值写到pdthread变量中,传递给函数PDthreadSelect(因为此函数只能有一个参数) */
void PDthreadCreate(pthread_t thread[], PDthread *pdthread, Nodes *node, char *dbname, char *query)
{
int tmp;
int i;
PDthread *p;
for (i=0; i<node->count; i++)
{
// 把Nodes作为PDthread的一部分
p = pdthread + i;
p->host = node->host[i];
p->port = node->port[i];
p->dbname = dbname;
p->query = query;
tmp = pthread_create(&thread[i], NULL, PDthreadSelect, p); if (tmp != 0) printf("PDthreadCreate: 线程%d创建失败!/n", i);
else printf("PDthreadCreate: 线程%d被创建/n", i);
}
}
void PDthreadWait(pthread_t thread[], int count)
{
// 等待线程结束
int i;
for (i=0; i<count; i++)
{
if (thread[i] != 0)
{
pthread_join(thread[i],NULL);
printf("线程%d已经结束/n", i);
}
}
}
int main()
{
Nodes node; node.count = 3;
strcpy(node.host[0], "192.168.0.1");
node.port[0] = 5432;
strcpy(node.host[1], "192.168.0.2");
node.port[1] = 5432;
strcpy(node.host[2], "192.168.0.3");
node.port[2] = 5432; //使用多线程去获取数据
pthread_t thread[MAX];
memset(&thread, 0, sizeof(thread)); // 获取结果
PDthread *pdthread = (PDthread *)malloc(node.count * sizeof(PDthread));
PDthreadCreate(thread, pdthread, &node, "database", "SELECT * FROM
student");
PDthreadWait(thread, node.count); // 返回结果存储在pdthread->rst
return 0;
}
编译命令:gcc -I/usr/local/pgsql/include -o th th.c -L/usr/local/pgsql/lib -lpq -lpthread,因为使用了libpq库。

Linux下通过共享内存进行进程间通信,进程间同步使用信号量来实现(Linux 环境下C编程指南)
Linux 环境下C编程指南,通过共享内存进行进程间通信的例子,进程间同步使用信号量来实现。

使用说明:这是一个简单的服务器和客户端程序,如果启动程序时不带参数,则执行服务器程序;
如果带参数,则执行客户端程序,所带参数只有一个,就是服务器端所显示的共享内存的引用ID。

实现原理:服务器端启动后,创建信号量和共享内存,并将共享内存的引用ID显示出来,将信号量
的引用ID存放在共享内存中。

客户端启动后,利用服务器端提供的内存共享ID将共享内存附加到地址段,读取信号量以实现两个进程之间的同步。

之后,这两个进程就可以利用共享内存进行进程间通信,客户端输入的信息将在服务器端显示出来。

#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/shm.h>
#define SHMDATASIZE 1000
#define BUFFERSIZE (SHMDATASIZE - sizeof(int))
#define SN_EMPTY 0
#define SN_FULL 1
int deleteSemid=0;
union semun
{
int val;
struct semid_ds *buf;
unsigned short int *array;
struct seminfo *__buf;
};
void server(void); //不加参数时执行
void client(int shmid);
void delete(void);
void sigdelete(int signum);
void locksem(int semid, int semnum);
void unlocksem(int semid, int semnum);
void waitzero(int semid, int semnum);
void clientwrite(int shmid, int semid, char *buffer);
int safesemget(key_t key, int nsems, int semflg);
int safesemctl(int semid, int semnum, int cmd, union semun arg); int safesemop(int semid, struct sembuf *sops, unsigned nsops); int safeshmget(key_t key, int size, int shmflg);
void *safeshmat(int shmid, const void *shmaddr, int shmflg); int safeshmctl(int shmid, int cmd, struct shmid_ds *buf);
int main(int argc, char *argv[])
{
if ( argc < 2 )
{
server();
}
else
{
client(atoi(argv[1]));
}
return 0;
}
void server(void)
{
union semun sunion;
int semid,shmid;
void *shmdata;
char *buffer;
semid = safesemget(IPC_PRIVATE, 2, SHM_R|SHM_W);
deleteSemid = semid;
atexit(&delete); //当程序终止执行时,执行 delete 函数
signal(SIGINT, &sigdelete); //接收到信号 SIGINT 则执行 sigdelete 函数
sunion.val = 1;
safesemctl(semid, SN_EMPTY, SETVAL, sunion);
sunion.val = 0;
safesemctl(semid, SN_FULL, SETVAL, sunion);
shmid = safeshmget(IPC_PRIVATE, SHMDATASIZE, IPC_CREAT|SHM_R|SHM_W);
shmdata = safeshmat(shmid, 0, 0);
safeshmctl(shmid, IPC_RMID, NULL); //删除共享内存,当所有附加该共享内存的进程结束或断开与该共享内存的连接时才执行
*(int *)shmdata = semid;
buffer = shmdata + sizeof(int);
printf("Server is running with SHM id ** %d **\n", shmid);
while(1)
{
printf("Waiting until full...");
fflush(stdout);
locksem(semid, SN_FULL);
printf("done.\n");
printf("Message received: %s.\n", buffer);
unlocksem(semid, SN_EMPTY);
}
}
void client(int shmid)
{
int semid;
void *shmdata;
char *buffer;
shmdata = safeshmat(shmid, 0, 0);
semid = *(int *)shmdata;
buffer = shmdata + sizeof(int);
printf("Client operational: shm id is %d, sem id is %d\n", shmid, semid);
while(1)
{
char input[3];
printf("\n\nMenu\n1.send a message\n");
printf("2.Exit\n");
fgets(input, sizeof(input), stdin);
switch(input[0])
{
case '1': clientwrite(shmid, semid, buffer);
break;
case '2': exit(0);
break;
}
}
}
void delete(void)
{
printf("\nMaster exiting; deleting semaphore %d.\n", deleteSemid);
if (semctl(deleteSemid, 0, IPC_RMID, 0) == -1 )
{
printf("Error releasing semaphore.\n");
}
}
void sigdelete(int signum)
{
exit(0);
}
void locksem(int semid, int semnum)
{
struct sembuf sb;
sb.sem_num = semnum;
sb.sem_op = -1;
sb.sem_flg = SEM_UNDO;
safesemop(semid, &sb, 1);
}
void unlocksem(int semid, int semnum)
{
struct sembuf sb;
sb.sem_num = semnum;
sb.sem_op = 1;
sb.sem_flg = SEM_UNDO;
safesemop(semid, &sb, 1);
}
void waitzero(int semid, int semnum)
{
struct sembuf sb;
sb.sem_num = semnum;
sb.sem_op = 0;
sb.sem_flg = 0;
safesemop(semid, &sb, 1);
}
void clientwrite(int shmid, int semid, char *buffer) {
printf("Waiting until empty...");
fflush(stdout);
locksem(semid, SN_EMPTY);
printf("done.\n");
printf("Enter Message: ");
fgets(buffer, BUFFERSIZE, stdin);
unlocksem(semid, SN_FULL);
}
int safesemget(key_t key, int nsems, int semflg)
{
int retval;
if ( (retval=semget(key, nsems, semflg)) == -1)
{
printf("semget error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
int safesemctl(int semid, int semnum, int cmd, union semun arg) {
int retval;
if ( (retval=semctl(semid, semnum, cmd, arg)) == -1)
{
printf("semctl error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
int safesemop(int semid, struct sembuf *sops, unsigned nsops) {
int retval;
if ( (retval=semop(semid, sops, nsops)) == -1)
{
printf("semop error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
int safeshmget(key_t key, int size, int shmflg)
{
int retval;
if ( (retval=shmget(key, size, shmflg)) == -1)
{
printf("shmget error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
void *safeshmat(int shmid, const void *shmaddr, int shmflg)
{
void *retval;
if ( (retval=shmat(shmid, shmaddr, shmflg)) == (void *)-1) {
printf("shmat error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
int safeshmctl(int shmid, int cmd, struct shmid_ds *buf)
{
int retval;
if ( (retval=shmctl(shmid, cmd, buf)) == -1)
{
printf("shmctl error: %s.\n", strerror(errno));
exit(254);
}
return retval;
}
--------------------------------
atexit
语法:
#include <stdlib.h> int atexit( void (*func)(void) );
功能:当程序终止执行时,函数调用函数指针func所指向的函数。

可以执行多重调用(至少32个),这些函数以其注册的倒序执行。

执行成功返回零值,失败则返回非零值。

相关文档
最新文档