linuxUnix多线程多进程编程总结(一)
接口说明:
int shmget(key_t key, size_t size, int shmflg); //创建共享内存
key: 共享内存id.
size: 共享内存大小.
shmflg: 权限标志,与文件权限相同.
返回值:成功返回0,失败返回-1.
void *shmat(int shm_id, const void *shm_addr, int shmflg); //连接共享内存
shm_id:共享内存Id.
shm_addr: 制定共享内存连接到当前进程中的位置,通常为空,表示让系统来选择共享内存的地址.
shm_flg: 标志位,通常为0
返回值:成功返回0,失败返回-1
int shmdt(const void *shmaddr); //分离共享内存,并不是删除,删除需要通过shmctl来操作.
shmaddr为shmat返回的共享内存位置指针。
返回值:成功返回0,失败返回-1
int shmctl(int shm_id, int command, struct shmid_ds *buf); //控制共享内存
shm_id:共享内存标识.
command: IPC_STAT, IPC_SET, IPC_RMID.
buf: buf为shmid_ds结构,用来存储要设置的共享内存参数,这个参数会传递给系统内核.
#include
#include
#include
#include
#include
#define SHARE_MEM_KEY 1234
int main(int argc, char ** argv) {
int shmId = 0; //共享内存标识
void * shm = NULL; //共享内存指针
pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;
shmId = shmget((key_t)SHARE_MEM_KEY, sizeof(int), 0666|IPC_CREAT);
if(shmId == -1) {
printf("shmget failed.\n");
exit(0);
}
printf("Memory attached at: %x\n", (int)shm);
//读共享内存
while(1) {
sleep(1);
int value = 0;
pthread_mutex_lock(&shm_mutex);
value = *(int *)shm;
pthread_mutex_unlock(&shm_mutex);
if(value != 0) {
printf("The value is: %d\n", value);
}
}
return 0;
}
- 共享内存写入端代码:
#include
#include
#include
#include
#include
#define SHARE_MEM_KEY 1234
int main(int argc, char ** argv) {
int i = 0;
int shmId = 0; //共享内存标识
void * shm = NULL; //共享内存指针
pthread_mutex_t shm_mutex = PTHREAD_MUTEX_INITIALIZER;
shmId = shmget((key_t)SHARE_MEM_KEY, sizeof(int), 0666|IPC_CREAT);
if(shmId == -1) {
printf("shmget failed.\n");
exit(0);
}
shm = shmat(shmId, 0, 0);
if(shm == (void*)-1) {
printf("shmat failed.\n");
exit(0);
}
printf("Memory attached at: %x\n", (int)shm);
//写共内存
while(1) {
sleep(1);
pthread_mutex_lock(&shm_mutex);
*(int *)shm = ++i;
pthread_mutex_unlock(&shm_mutex);
int value = *(int *)shm;
printf("Writting value:%d\n", value);
}
return 0;
}
reader代码:
#include
#include
#include
#include
#define P_FIFO "/tmp/p_fifo"
int main( int argc, char ** argv ) {
int fd;
if(mkfifo(P_FIFO, 0777) < 0) { //构建有名管道
printf("Create named pipe failed.\n");
}
fd = open(P_FIFO, O_RDONLY); //阻塞方式
while(1) {
char buf[100];
int count = 0;
memset(buf, 0, sizeof(buf));
count = read(fd, buf, 100); //因为以阻塞方式打开,所以没有数据会导致阻塞。
//一旦阻塞的read被触发后就不会再次被阻塞了。
//所以这里要判断read的返回值,当read返回0的时候代表读到了文件尾,此时buffer为空,就不需要打印。
if(count != 0) {
printf("Count: %d, %s\n",count, buf);
}
}
close(fd); //虽然不会走到这里,写在这做备忘。
return 0;
}
writter代码:
#include
#include
#include
#include //包含O_WRONLY O_RDONLY这些宏定义。
#define P_FIFO "/tmp/p_fifo"
int main(int argc, char ** argv) {
int i = 0;
int fd = open(P_FIFO, O_WRONLY); //非阻塞方式
//while(1) {
for(i = 0;i< 2;i++) {
write(fd, argv[1], 100);
printf(".");
sleep(1);
}
close(fd);
return 0;
}
int msgget(key_t key, int msgflag); //创建和访问一个消息队列。
msgflag是权限标志,表示消息队列的访问权限,它与文件的访问权>限一样。
msgflag | IPC_CREAT表示当key命令的消息队列不存在的时候创建一个消息队列。
如果key命令的消息队列存在,则返回这个消息>队列的标识符。失败时返回-1。
int msgsend(int msgid, const void * msg_ptr, size_t msg_sz, int msgflag);
msgid:msgget返回的消息队列标识符。
msg_ptr:消息结构指针。
msg_sz:消息结构大小。
成功返回0,失败返回-1。
int msgrcv(int msgid, void * msg_ptr, size_t msg_st, long msgtype, int msgflag);
msgid:消息队列id。
msg_ptr: 消息buffer指针。
msg_st: 消息buffer大小。
msgtype:消息优先级,msgtype==0,获取队列的第一个消息;msgtype>0,获取消息队列中同等类型的消息。
msgtype<0,获取类型等于或者小于msgtype绝对值的第一个消息。
成功返回读取的字节数,失败返回-1。
int msgctl(int msgid, int command, struct msgid_ds * buf);
command可以去三个值:
IPC_STAT:获得消息状态;
IPC_SET:设置消息状态;
IPC_RMID:删除消息队列;
成功返回0,失败返回-1。
#include
#include
#include
#include
#include
#define MAX_TEXT 200
struct msg_st {
long msg_type;
char text[MAX_TEXT];
};
int main(int argc, char ** argv) {
int running = 1;
char buffer[MAX_TEXT];
int msgid = -1;
struct msg_st data;
msgid = msgget((key_t)1234, 0666|IPC_CREAT);
if(msgid == -1) {
printf("Msgget failed with error:%d\n", errno);
exit(0);
}
while(running) {
printf("Enter some text:\n");
fgets(buffer, MAX_TEXT, stdin);
data.msg_type = 1;
strcpy(data.text, buffer);
if(msgsnd(msgid, (void *)&data, MAX_TEXT, 0) == -1) {
printf("Msgsnd failed.\n");
exit(0);
}
if(strncmp(buffer, "end", 3) == 0) {
printf("Setting running as 0.\n");
running = 0;
}
sleep(1);
}
return 0;
}
#include
#include
#include
#include
#include
#define BUFSIZE 200
struct msg_st {
long msg_type;
char text[BUFSIZE];
};
int main(int argc, char ** argv) {
int msgid = -1;
int running = 1;
struct msg_st data;
long msgtype = 0;
msgid = msgget((key_t)1234, 0666|IPC_CREAT); //创建消息队列
if(msgid == -1) {
printf("Msgget failed with error:%d\n", errno);
exit(0);
}
while(running) {
if(msgrcv(msgid, (void *)&data, BUFSIZ, msgtype, 0) == -1){
printf("msgrcv failed with errno:%d\n", errno);
exit(0);
}
printf("You wrote:%s\n", data.text);
if(strncmp(data.text, "end", 3) == 0) {
printf("Received msg end.\n");
running = 0;
}
}
if(msgctl(msgid, IPC_RMID, 0) == -1) {
printf("Msgctl error.\n");
exit(0);
}
return 0;
}
rlen = recv(sock_fd, buf, len, MSG_WAITALL);
if((rlen == -1) && (errno == EINTR)) {
//说明这个recv错误是由于recv函数被中断了引起的,我们可以把rlen设置为0,然后重新执行recv就可以了。
}
几个讲解linux信号机制比较好的连接
代码示例:
#include
#include
#include
#define TEST_SIGRTMIN 34
//信号处理函数,函数原型 void function(int signo);
void signal_handler(int signo) {
printf("====>signo %x\n", signo);
switch(signo) {
case TEST_SIGRTMIN:
printf("signal SIGRTMIN.\n");
break;
case SIGUSR2:
printf("signal SIGUSR2.\n");
break;
case SIGUSR1:
printf("Signal SIGUSR1.\n");
break;
case SIGINT:
printf("====>SIGINT comes.\n");
//signal(SIGINT, SIG_DFL);
break;
default:
printf("Receive signal number %d\n", signo);
break;
}
//exit(0); //收到SIGINT信号之后程序退出。
}
int main(int argc, char ** argv) {
sigset_t initset;
int i;
sigemptyset(&initset);
sigaddset(&initset, SIGINT); //将SIGINT信号加入到信号集合中。
sigaddset(&initset, SIGUSR1); //把信号SIGUSR1加入到信号集合中。
sigaddset(&initset, SIGUSR2); //把信号SIGUSR2加入到信号集合中。
sigaddset(&initset, TEST_SIGRTMIN); //实时信号,可以排队;非实时信号不能排队。
signal( SIGINT, SIG_IGN ); //忽略信号SIGINT
for(i = 0; i < 10; i++) { //在此for循环期间输入终端信号,程序没有反应,不会退出。
sleep(1);
printf("Input crtl+C now. But this program will ignore it.\n");
}
signal(SIGINT, SIG_DFL); //对信号采用默认的处理方式
sigprocmask(SIG_BLOCK, &initset, NULL); //阻塞中断信号
for(i = 0;i < 20; i++) {
sleep(1);
printf("Input ctrl+C now.But the signal is blocked.\n"); //此时输入信号信号会阻塞。
}
signal(SIGINT, signal_handler); //注册信号处理函数。
signal(SIGRTMIN, signal_handler);
sigprocmask(SIG_UNBLOCK, &initset, NULL); //设置信号为非阻塞,也就是从这之后系统开始接收中断信号了。
for(i = 0;i < 10; i++) {
sleep(1);
printf("Input ctrl+C now.The signal is handled by this program.\n");
}
return 0;
}
/*
* 测试结果:
* SIG_IGN会使得信号被传递到程序,然后被程序忽略。
* SIG_DFL使得程序按照默认的方式处理信号。
* 阻塞信号的时候内核会暂存程序的信号,信号在阻塞状态的时候不会被传递到程序,知道解除阻塞。
* 对与0~31的非可靠信号,解除阻塞之后在阻塞阶段发生的信号会被传递给程序,但是对于多个相同的信号只传递一次。
* 例如阻塞了三个信号SIGINT,SIGUSR1,SIGUSR2,如果在阻塞期间内,这几个信号到来,那么不会立即传递给应用程序,而是等到解除阻塞之后,最早的一个信号会被发送给程序,其余的信>号就被丢弃了,程序是感觉不到有后续信号发过来的。例如:在阻塞过程中发送的信号顺序为SIGUSR1,SIGINT,SIGUSR2,那么解除阻塞之后只有SIGUSR1会被程序处理,而程序根本感觉不到信号SIGINT和SIGUSR2。
* 对于可靠信号(kill -l:34~64),例如SIGRTMIN信号阻塞了,在阻塞期间如果有5个SIGRTMIN信号发送给程序,那么这5个信号会缓存起来,等待信号不再阻塞之后5个信号都能被程序接收到
,这和不可靠信号(1~31)是不同的。
* */