4、共享内存
/*
是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入了数据,共享这个内存区域的所有进程就可以立刻看到其中的内容.
共享内存实现分为两个步骤:
一、创建共享内存,使用shmget函数
二、映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数
*/
#include<sys/shm.h>
int shmget ( key_t key, int size, int shmflg )
/*
key:标识共享内存的键值: 0/IPC_PRIVATE。
当key的取值为IPC_PRIVATE,则函数shmget()将创建一块新的共享内存;
如果key的取值为0,而参数shmflg中又设置IPC_PRIVATE这个标志,则同样会创建一块新的共享内存。
size:以字节为单位,实际按页分配,每页4K = 4096 bytes
shmflg:
权限
IPC_CREAT:如果共享内存不存在,则创建一个共享内存,否则打开操作。
IPC_EXCL:只有在共享内存不存在的时候,新的共享内存才建立,否则就产生错误。
返回值:如果成功,返回共享内存标识符;如果失败,返回-1
*/
char * shmat ( int shmid, char *shmaddr, int flag)
/*
shmid:shmget函数返回的共享存储标识符
shmaddr:指定共享内存映射到进程中的地址,通常不指定,写NULL
flag:决定以什么方式来确定映射的地址,通常写0
SHM_RDONLY
SHM_WRONLY
返回值:如果成功,则返回共享内存映射到进程中的地址;如果失败,则返回-1,(char *)(-1)
*/
int shmdt ( char *shmaddr )
/*
当一个进程不再需要共享内存时,需要把它从进程地址空间中脱离。
*/
int shmctl(int shmid,int cmd,struct shmid_ds * buf)
/*
shmid:shmget函数返回的共享存储标识符
cmd:
IPC_STAT:查看状态
IPC_SET:将设置的属性改到共享内存中
IPC_RMID:删除shmid对应的共享内存
buf:缓冲区,通常写NULL
*/
/*
*/
5、消息队列
/*
消息队列就是一个消息的链表.可以把消息看作一个记录,具有特定的格式.进程可以向中按照一定的规则添加新消息;另一些进程则可以从消息队列中读走消息
消息队列的内核持续性要求每个消息队列都在系统范围内对应唯一的键值,所以,要获得一个消息队列的描述字,必须提供该消息队列的键值
系统V消息队列是随内核持续的,只有在内核重起或者人工删除时,该消息队列才会被删除
*/
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok (char*pathname, char proj)
/*
功能:返回文件名对应的键值。
pathname:文件名
proj:项目名(不为0即可)
*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
int msgget(key_t key, int msgflg)
/*
key:键值,由ftok获得。
msgflg:标志位。
IPC_CREAT:创建新的消息队列
IPC_EXCL:与IPC_CREAT一同使用,表示如果要创建的消息队列已经存在,则返回错误。
IPC_NOWAIT:读写消息队列要求无法得到满足时,不阻塞
返回值:与健值key相对应的消息队列描述字
在以下两种情况下,将创建一个新的消息队列:
1、如果没有与健值key相对应的消息队列,并且 msgflg中包含了IPC_CREAT标志位。
2、key参数为IPC_PRIVATE
*/
int msgsnd(int msqid,struct msgbuf*msgp,int msgsz,int msgflg)
struct msgbuf{
long mtype;/*消息类型(编号)*/
char mtext[?]; /*消息数据的首地址*/
}
/*
功能:向消息队列中发送一条消息
msqid:已打开的消息队列id
msgp:存放消息的结构,起始位置
msgsz:消息数据长度,字节数
msgflg:发送标志,有意义的msgflg标志为IPC_NOWAIT,指明在消息队列没有足够空间容纳要发送的消息时,msgsnd是否等待
返回值:返回实际发送的长度
-1:出错
*/
int msgrcv(int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, int msgflg)
/*
功能:
从msqid代表的消息队列中读取一个msgtyp类型的消息,并把消息存储在msgp指向的msgbuf结构中。
在成功地读取了一条消息以后,队列中的这条消息将被删除
msgtpe:消息类型(编号)
0:完全依照先进先出原则,取第一个进入消息队列的消息
>0:从消息队列中第一个开始,往后找第一个消息类型等于该值的消息
<0:取绝对值,从消息队列中第一个开始,往后找第一个消息类型小于绝对值的消息
返回值:返回实际接收的长度
-1:出错
*/
三、线程
/*
线程由进程创建,线程的任务只能属于创建自己的进程
线程没有自己的资源,只能等待进程分配
线程(thread)技术早在60年代就被提出,但真正应用多线程到操作系统中去,是在80年代中期,solaris是这方面的佼佼者。传统的Unix也支持线程的概念,但是在一个进程(process)中只允许有一个线程,这样多线程就意味着多进程。现在,多线程技术已经被许多操作系统所支持,包括Windows/NT、Linux
使用多线程的理由之一是:
和进程相比,它是一种非常“节俭”的多任务操作方式.在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式,运行于一个进程中的多个线程,它们之间使用相同的地址空间,而且线程间彼此切换所需的时间也远远小于进程间切换所需要的时间.据统计,一个进程的开销大约是一个线程开销的30倍左右
使用多线程的理由之二是:
线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过进程间通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便
除了以上所说的优点外,多线程程序作为一种多任务、并发的工作方式,有如下优点:
使多CPU系统更加有效.操作系统会保证当线程数不大于CPU数目时,不同的线程运行于不同的CPU上.改善程序结构.一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改.
因为pthread的库不是linux系统的库,所以在进行编译的时候要加上-lpthread gcc filename -lpthread
*/
1、创建
#include <pthread.h>
int pthread_create(pthread_t *tidp,const pthread_attr_t *attr,void*(*start_rtn)(void/void *),void*arg)
/*
tidp:线程id,pthread_t id;使用时&id
attr:线程属性(通常为NULL)
start_rtn:线程要执行的函数,当后一个参数为NULL时,此时该函数参数写void*。否则写void
arg:start_rtn的参数
返回值:成功返回0,不成功返回-1
*/
void pthread_exit(void * rval_ptr)
/*
功能:终止调用线程 线程退出不可以用exit或_exit,这两个函数结束进程
Rval_ptr:线程退出返回值的指针
*/
int pthread_join(pthread_t tid,void **rval_ptr)
/*
功能:阻塞调用线程,直到指定的线程终止。主线程等工作进程结束,返回到join的位置
tid:等待退出的线程id
rval_ptr:线程退出的返回值的指针,exit的带回来的参数
*/
int pthread_self()
/*
功能:获取线程id
*/
2、退出
/*
如果进程中任何一个线程中调用exit或_exit,那么整个进程都会终止。线程的正常退出方式有:
(1) 线程从启动例程中返回
(2) 线程可以被另一个进程终止pthread_cance(pthread_t tid)
(3) 线程自己调用pthread_exit函数
*/
/*
*/
#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<sys/types.h>
#include<string.h>
#include<unistd.h>
char message[]="hello world";
void *thread_func(void *arg){
printf("thread function is running!");
printf("argument is %s\n",(char *)arg);
sleep(3);
strcpy(message,"bye");
pthread_exit("thank you for your cpu time!");
}
int main(int argc, char const *argv[]){
pthread_t tid;
int ret;
void *thread_result=NULL;
ret=pthread_create(&tid,NULL,thread_func,(void *)message);
if(ret!=0){
perror("create pthread error!");
exit(-1);
}
printf("waiting for thread finish...\n");
ret=pthread_join(tid,&thread_result); //阻塞等待,等待子线程结束否则主线程不运行
if(ret!=0){
perror("join error!");
exit(-1);
}
printf("thread joined , it returned :%s\n",(char *)thread_result);
printf("message is now :%s\n",message);
return 0;
}