进程线程
来源:互联网 发布:苏州梯田软件 编辑:程序博客网 时间:2024/06/07 11:21
2.可中断的阻塞状态
3.不可中断的阻塞状态
4.暂停状态
5.僵死状态
6.消亡状态
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #define BUF_SIZE 100
- #define ARR_SIZE 10
- enum ERROR_TYPE
- {
- ERROR = -1,
- OK
- };
- int FuncArr(char *p, char *pArr[])
- {
- if (NULL == p || NULL == pArr)
- {
- return ERROR;
- }
- *pArr = p;
- pArr++;
- p++;
- while(*p)
- {
- if (' ' == *(p-1) && '\0' != *p)
- {
- *pArr = p;
- *(p-1) = '\0';
- pArr++;
- }
- p++;
- }
- return OK;
- }
- int main()
- {
- char buf[BUF_SIZE] = {0};
- pid_t pid = -1;
- char *strArr[ARR_SIZE] = {NULL};
- while(1)
- {
- memset(buf, 0, BUF_SIZE);
- memset(strArr, 0, sizeof(strArr));
- gets(buf);
- if (OK != FuncArr(buf, strArr))
- {
- continue;
- }
- pid = fork();
- if (-1 == pid)
- {
- perror("fork");
- return ERROR;
- }
- else if (0 == pid)
- {
- if (-1 == execvp(strArr[0], strArr))
- {
- perror("execvp");
- }
- exit(1);
- }
- else
- {
- wait(NULL);
- }
- }
- }
- #include <stdio.h>
- #include <pthread.h>
- void * ThreadFunc(void *arg)
- {
- printf("hello\r\n");
- //pthread_exit("aaaaaa ddddd");
- }
- int main()
- {
- pthread_t tId;
- if (0 != pthread_create(&tId, NULL, ThreadFunc, NULL))
- {
- printf("create thread error\r\n");
- return -1;
- }
- //sleep(1); 如果没有sleep函数,线程共享的地址被释放,就不会打印结果。
- //char *pTmp = NULL;
- //pthread_join(tId, (void **)&pTmp);
- //printf("%s\r\n", pTmp);
- pthread_join(tId, NULL);
- return 0;
- }
- 创建子进程,父进程退出
- 在子进程中创建新会话(这是最重要的一步)
- 了解setsid()函数之前要了解两个概念:进程组和会话期。进程组是一个或多个进程的集合,
- 进程组由进程组ID来唯一标识,除了进程号之外,进程组ID 也是进程的一个必备属性。
- 每个进程组都有一个组长进程,其组长进程的进程号等于进程组ID,且进程组ID不会因组长进程的退出而受到影响。
- 会话期:会话期是一个或多个进程的集合。通常,一个会话开始于用户登录,终止于用户退出,或者开始于终端打开,结束于终端关闭。
- setsid()函数用于创建一个新的会话,并担任该会话组的组长,调用setsid()函数有下面的三个作用:
- 让进程摆脱原会话的控制。
- 让进程摆脱原进程组的控制。
- 让进程摆脱原控制终端的控制。
- 改变当前目录为根目录
- 重设文件权限掩码
- 关闭文件描述符
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int main()
- {
- pid_t pid = -1;
- pid = fork();
- if (-1 == pid)
- {
- printf("fork error\r\n");
- return -1;
- }
- if (pid > 0) //父进程退出
- {
- exit(0);
- }
- //create session
- setsid();
- chdir("/"); 改变当前目录
- umask(0); 重设文件权限掩码
- int iFdSize = getdtablesize();
- int fd = 0;
- for (; ifd< iFdSize; fd++) 关闭文件描述符
- {
- close(fd);
- }
- sleep(10);
- return 0;
- }
- 可执行的命令
- 静态数据
- 进程中打开的文件描述符
- 信号处理函数
- 当前工作目录
- 用户ID
- 用户组ID
- 线程ID
- PC 计数器和相关寄存器
- 堆栈
- 局部变量
- 返回地址
- 错误号
- 信号掩码和优先级
- 执行状态和属性
- int pthread_exit(void *value_ptr)
- value_ptr 线程退出时返回的值
- int pthread_cancel(pthread_t thead)
- thread: 要取消的线程
- 成功 1
- 错误 -1
- #include <stdio.h>
- #include <pthread.h>
- #include <stdlib.h>
- void * ThreadFunc(void *arg)
- {
- //int *p = (int *)arg;
- //int b = *((int *)arg);
- int *p = malloc(sizeof(int));
- *p = *((int *)arg);
- printf("hello %d\r\n", *p);
- }
- int main()
- {
- pthread_t tId;
- int a = 10;
- if (0 != pthread_create(&tId, NULL, ThreadFunc, (void *)&a))
- {
- printf("create thread error\r\n");
- return -1;
- }
- pthread_join(tId, NULL);
- return 0;
- }
- #include <stdio.h>
- #include <pthread.h>
- void * ThreadFunc(void *arg)
- {
- printf("hello\r\n");
- //pthread_exit("aaaaaa ddddd");
- }
- int main()
- {
- pthread_t tId;
- if (0 != pthread_create(&tId, NULL, ThreadFunc, NULL))
- {
- printf("create thread error\r\n");
- return -1;
- }
- //sleep(1);
- //char *pTmp = NULL;
- //pthread_join(tId, (void **)&pTmp);
- //printf("%s\r\n", pTmp);
- pthread_join(tId, NULL);
- return 0;
- }
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <pthread.h>
- void *Func(void *arg)
- {
- char *pTmp = (char *)arg;
- #ifndef MALLOC_MEMORY
- static char s_arr[11] = {0};
- #else
- printf("malloc\r\n");
- char *s_arr = (char *) malloc (11);
- if (NULL == s_arr)
- {
- return (void *)NULL;
- }
- memset(s_arr, 0, 11);
- #endif
- int i = 0;
- for(; i < 10; i++)
- {
- s_arr[i] = pTmp[i];
- //usleep(2000);
- //sleep(1);
- }
- printf("%s\r\n", s_arr);
- #ifdef MALLOC_MEMORY
- free(s_arr);
- s_arr = NULL;
- #endif
- }
- int main()
- {
- pthread_t tID1;
- pthread_t tID2;
- char arr1[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
- char arr2[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
- if (0 != pthread_create(&tID1, NULL, Func, (void *)arr1))
- {
- return -1;
- }
- if (0 != pthread_create(&tID2, NULL, Func, (void *)arr2))
- {
- return -1;
- }
- pthread_join(tID1, NULL);
- pthread_join(tID2, NULL);
- return 0;
- }
- #include <stdio.h>
- #include <pthread.h>
- pthread_mutex_t g_mutex;
- void *Func(void *arg)
- {
- pthread_mutex_lock(&g_mutex);
- char *pTmp = (char *)arg;
- if (NULL == pTmp)
- {
- pthread_mutex_unlock(&g_mutex);
- return (void *)NULL;
- }
- static char s_arr[11] = {0};
- int i = 0;
- for(; i < 10; i++)
- {
- s_arr[i] = pTmp[i];
- //usleep(2000);
- sleep(1);
- }
- printf("%s\r\n", s_arr);
- pthread_mutex_unlock(&g_mutex);
- }
- int main()
- {
- pthread_t tID1;
- pthread_t tID2;
- char arr1[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'};
- char arr2[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'};
- if (0 != pthread_mutex_init(&g_mutex, NULL))
- {
- return -1;
- }
- if (0 != pthread_create(&tID1, NULL, Func, (void *)arr1))
- {
- return -1;
- }
- if (0 != pthread_create(&tID2, NULL, Func, (void *)arr2))
- {
- return -1;
- }
- pthread_join(tID1, NULL);
- pthread_join(tID2, NULL);
- return 0;
- }
- 初始化
- P操作(申请资源)
- V操作(释放资源)
- 无名信号量
- 有名信号量
- #include <stdio.h>
- #include <pthread.h>
- #include <semaphore.h>
- sem_t g_sem1;
- sem_t g_sem2;
- void *Func1(void *arg)
- {
- int i = 10;
- while(i--)
- {
- sem_wait(&g_sem1);
- printf("hello\r\n");
- sleep(1);
- sem_post(&g_sem2);
- }
- }
- void *Func2(void *arg)
- {
- int i = 10;
- while(i--)
- {
- sem_wait(&g_sem2);
- printf("world\r\n");
- sleep(1);
- sem_post(&g_sem1);
- }
- }
- int main()
- {
- pthread_t tId1;
- pthread_t tId2;
- if (0 != sem_init(&g_sem1, 0, 1) || 0 != sem_init(&g_sem2, 0, 0))
- {
- return -1;
- }
- if (0 != pthread_create(&tId1, NULL, Func1, NULL))
- {
- return -1;
- }
- if (0 != pthread_create(&tId2, NULL, Func2, NULL))
- {
- return -1;
- }
- pthread_join(tId1, NULL);
- pthread_join(tId2, NULL);
- return 0;
- }
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- int main()
- {
- pid_t pid, ret;
- if ((pid == fork()) < 0)
- {
- printf("error fork\r\n");
- return -1;
- }
- else if (pid == 0) //子进程
- {
- //子进程暂停5秒
- sleep(5);
- //子进程正常退出
- exit(0);
- }
- else //父进程
- {
- //循环测试子进程是否退出
- do
- {
- //调用waitpid ,且父进程不阻塞
- //ret = waitpid(pid,NULL,WNOHANG); //WNOHANG:若指定的子进程没有结束,则waitpid不阻塞而立即返回,此时返回值为零
- //如果改为ret = waitpid(pid, NULL, 0);父进程会一直阻塞
- ret = waitpid(pid, NULL, 0);
- //若子进程未退出,则父进程暂停1s
- //若子进程退出,waitpid返回子进程号,若没有子进程退出,waitpid返回0
- if (ret == 0)
- {
- printf("The child process has not exited,pid = %d\n", getpid());
- sleep(1);
- }
- } while (ret == 0);
- //若发现子进程退出, 打印出相应信息
- if (pid == ret)
- {
- printf("child process exited,pid = %d\n", getpid());
- }
- else
- {
- printf("some error occured.\n");
- }
- }
- }
一、进程间的通信方式
# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。
进程的亲缘关系通常是指父子进程关系。
# 有名管道 (namedpipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
# 信号量(semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。
它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。
因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( messagequeue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。
消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 (sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存(shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,是最有效的进程间通信方式。
这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,
它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,
如信号两,配合使用,来实现进程间的同步和通信。
# 套接字(socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,
它可用于不同及其间的进程通信。
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <signal.h>
- int main()
- {
- pid_t pid;
- int ret;
- //创建一子进程
- if ((pid = fork()) < 0)
- {
- printf("Fork error\r\n");
- exit(-1);
- }
- if (pid == 0)
- {
- //在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停
- printf("child (pid : %d) is waiting for any signal\r\n",getpid());
- raise(SIGSTOP);
- exit(0);
- }
- else
- {
- //在父进程中收集子进程的状态,并调用kill()函数发送信号
- if ((waitpid(pid,NULL,WNOHANG)) == 0)
- {
- kill(pid,SIGKILL);
- printf("parent kill child process %d\r\n",pid);
- }
- waitpid(pid,NULL,0);
- exit(0);
- }
- }
- #include <stdio.h>
- #include <unistd.h>
- #include <stdlib.h>
- int main()
- {
- //调用alarm函数
- alarm(5);
- pause();
- printf("I have been waken up.\r\n");//此语句不会被执行
- }
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #define BUF_SIZE 10
- struct MyBuf
- {
- long m_lType;
- char buf[BUF_SIZE];
- };
- int main()
- {
- key_t key = ftok(".", 15);
- if (-1 == key)
- {
- return -1;
- }
- printf("ftok ok\r\n");
- int iMsgID = msgget(key, IPC_CREAT | 0666);
- if (-1 == iMsgID)
- {
- return -1;
- }
- printf("msgget ok\r\n");
- //send msg
- struct MyBuf stBuf;
- memset(&stBuf, 0, sizeof(struct MyBuf));
- stBuf.m_lType = 6;
- strcpy(stBuf.buf, "ttt");
- int iRet = msgsnd(iMsgID, (void *)&stBuf, BUF_SIZE, 0);
- printf("%d\r\n", iRet);
- return 0;
- }
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #define BUF_SIZE 10
- struct MyBuf
- {
- long m_lType;
- char buf[BUF_SIZE];
- };
- int main()
- {
- key_t key = ftok(".", 15);
- if (-1 == key)
- {
- return -1;
- }
- printf("ftok ok\r\n");
- int iMsgID = msgget(key, IPC_CREAT | 0666);
- if (-1 == iMsgID)
- {
- return -1;
- }
- printf("msgget ok\r\n");
- //receive msg
- struct MyBuf stBuf;
- memset(&stBuf, 0, sizeof(struct MyBuf));
- int iRet = msgrcv(iMsgID, (void *)&stBuf, BUF_SIZE,6, 0);
- printf("%d %s\r\n", iRet, stBuf.buf);
- return 0;
- }
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #define BUFFER_SIZE 2048
- int main()
- {
- pid_t pid;
- int shmid;
- char *shm_addr;
- char flag[] = "WROTE";
- char buff[BUFFER_SIZE];
- //创建共享内存
- if ((shmid = shmget(IPC_PRIVATE,BUFFER_SIZE,0666)) < 0)
- {
- perror("shmget\r\n");
- exit(1);
- }
- else
- {
- printf("Create shared-memory:%d\r\n",shmid);
- }
- //显示共享内存情况
- system("ipcs -m");
- pid = fork();
- if (pid == -1)
- {
- perror("fork\r\n");
- exit(1);
- }
- else if (pid == 0)//子进程处理
- {
- //映射共享内存
- if ((shm_addr = shmat(shmid,0,0)) == (void *)-1)
- {
- perror("Child:shmat\r\n");
- exit(1);
- }
- else
- {
- printf("Child : Attach shared-memory: %p\r\n",shm_addr);
- }
- system("ipcs -m");
- //通过检查在共享内存的头部是否标志字符串WROTE来确认父进程已经向共享内存写入有效数据
- while (strncmp(shm_addr,flag,strlen(flag)))
- {
- printf("Child:wait for enable data...\r\n");
- sleep(5);
- }
- strcpy(buff,shm_addr+strlen(flag));
- printf("Child : shared-memory : %s\r\n",buff);
- //解除共享内存映射
- if ((shmdt(shm_addr)) < 0)
- {
- perror("shmdt");
- exit(1);
- }
- else
- {
- printf("Child : Deattach shared-memory\r\n");
- }
- system("ipcs -m");
- //删除共享内存
- if (shmctl(shmid,IPC_RMID,NULL) == -1)
- {
- perror("Child: shmctl(IPC_RMID)\r\n");
- exit(1);
- }
- else
- {
- printf("Delete shared-memory\r\n");
- }
- system("ipcs -m");
- }
- else //父进程处理
- {
- //映射共享内存
- if ((shm_addr = shmat(shmid,0,0)) == (void *)-1)
- {
- perror("Parent : shmat");
- exit(1);
- }
- else
- {
- printf("Parent: Attach shared-memory : %p\r\n",shm_addr);
- }
- sleep(1);
- printf("\nInput some string:\r\n");
- fgets(buff,BUFFER_SIZE,stdin);
- strncpy(shm_addr + strlen(flag),buff,strlen(buff));
- strncpy(shm_addr,flag,strlen(flag));
- //解除共享内存映射
- if ((shmdt(shm_addr)) < 0)
- {
- perror("Parent: shmdt");
- exit(1);
- }
- else
- {
- printf("Parent: Deattach shared-memory\r\n");
- }
- system("ipcs -m");
- waitpid(pid,NULL,0);
- printf("Finished\r\n");
- }
- exit(0);
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #define MAX_DATA_LEN 256
- int main()
- {
- pid_t pid;
- int pipe_fd[2];
- char buf[MAX_DATA_LEN];
- const char data[] = "Pipe test program";
- int real_read, real_write;
- memset(buf,0,sizeof(buf));
- if (pipe(pipe_fd) < 0)
- {
- perror("fail to pipe");
- exit(-1);
- }
- if ((pid = fork()) == 0)//创建子进程
- {
- close(pipe_fd[1]);//子进程关闭写描述符,并通过使子进程暂停1s等待父进程关闭相应的读描述符
- sleep(1);
- if ((real_read = read(pipe_fd[0],buf,MAX_DATA_LEN)) > 0)//子进程读取管道内容
- {
- printf("%d byte read from the pipe is '%s'\r\n",real_read,buf);
- }
- close(pipe_fd[0]);//关闭子进程读描述符
- exit(0);
- }
- else if (pid > 0)
- {
- close(pipe_fd[0]);//父进程关闭读描述符
- if ((real_write = write(pipe_fd[1],data,strlen(data))) != -1)
- {
- printf("parent wrote %d bytes:'%s'\r\n",real_write,data);
- }
- close(pipe_fd[1]);//关闭父进程写描述符
- waitpid(pid,NULL,0);//收集子进程退出信息
- exit(0);
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- int main()
- {
- pid_t pid;
- int ret;
- //创建子进程
- if ((pid = fork()) < 0)
- {
- printf("Fork error\n");
- exit(1);
- }
- if (pid == 0)
- {
- //在子进程中使用raise()函数发出SIGSTOP信号,使子进程暂停
- printf("child(pid : %d) is waiting for any signal\n",getpid());
- raise(SIGSTOP);
- exit(0);
- }
- else
- {
- //在父进程中收集子进程的状态,并调用kill()函数发送信号
- if((waitpid(pid, NULL, WNOHANG)) == 0)
- {
- kill(pid, SIGKILL);
- printf("parent kill child process %d\n",pid);
- }
- waitpid(pid, NULL, 0);
- exit(0);
- }
- }
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #define BUF_SIZE 10
- struct MyBuf
- {
- long m_lType;
- char buf[BUF_SIZE];
- };
- int main()
- {
- key_t key = ftok(".", 15);
- if (-1 == key)
- {
- return -1;
- }
- printf("ftok ok\r\n");
- int iMsgID = msgget(key, IPC_CREAT | 0666);
- if (-1 == iMsgID)
- {
- return -1;
- }
- printf("msgget ok\r\n");
- //receive msg
- struct MyBuf stBuf;
- memset(&stBuf, 0, sizeof(struct MyBuf));
- int iRet = msgrcv(iMsgID, (void *)&stBuf, BUF_SIZE,6, 0);
- printf("%d %s\r\n", iRet, stBuf.buf);
- return 0;
- }
- msg_send
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #define BUF_SIZE 10
- struct MyBuf
- {
- long m_lType;
- char buf[BUF_SIZE];
- };
- int main()
- {
- key_t key = ftok(".", 15);
- if (-1 == key)
- {
- return -1;
- }
- printf("ftok ok\r\n");
- int iMsgID = msgget(key, IPC_CREAT | 0666);
- if (-1 == iMsgID)
- {
- return -1;
- }
- printf("msgget ok\r\n");
- //send msg
- struct MyBuf stBuf;
- memset(&stBuf, 0, sizeof(struct MyBuf));
- stBuf.m_lType = 6;
- strcpy(stBuf.buf, "ttt");
- int iRet = msgsnd(iMsgID, (void *)&stBuf, BUF_SIZE, 0);
- printf("%d\r\n", iRet);
- return 0;
- }
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <linux/ipc.h>
- #include <linux/sem.h>
- #define BUF_SIZE 10
- int main()
- {
- key_t key = ftok(".", 16);
- if (-1 == key)
- {
- return -1;
- }
- printf("ftok ok\r\n");
- //create sem
- int iSemID = semget(key, 1, IPC_CREAT | 0666);
- if (-1 == iSemID)
- {
- return -1;
- }
- printf("semget ok\r\n");
- //set value
- union semun stSemInit;
- stSemInit.val = 1;
- int iRet = semctl(iSemID, 0, SETVAL, stSemInit);
- if (-1 == iRet)
- {
- semctl(iSemID, 0, IPC_RMID);
- return -1;
- }
- printf("set val ok\r\n");
- // p v
- pid_t pid = fork();
- if (pid < 0)
- {
- semctl(iSemID, 0, IPC_RMID);
- return -1;
- }
- struct sembuf stBuf;
- if (0 == pid)
- {
- stBuf.sem_num = 0;
- stBuf.sem_op = -1;
- stBuf.sem_flg = SEM_UNDO;
- semop(iSemID, &stBuf, 1);
- printf("hello\r\n");
- sleep(5);
- stBuf.sem_num = 0;
- stBuf.sem_op = 1;
- stBuf.sem_flg = SEM_UNDO;
- semop(iSemID, &stBuf, 1);
- exit(0);
- }
- else
- {
- sleep(1);
- stBuf.sem_num = 0;
- stBuf.sem_op = -1;
- stBuf.sem_flg = SEM_UNDO;
- semop(iSemID, &stBuf, 1);
- printf("world\r\n");
- stBuf.sem_num = 0;
- stBuf.sem_op = 1;
- stBuf.sem_flg = SEM_UNDO;
- semop(iSemID, &stBuf, 1);
- wait(NULL);
- semctl(iSemID, 0, IPC_RMID);
- }
- return 0;
- }
- #include <stdio.h>
- #include <fcntl.h> /* For O_* constants */
- #include <sys/stat.h> /* For mode constants */
- #include <semaphore.h>
- int main()
- {
- sem_t *pSem1 = sem_open("aaa", O_CREAT, 0666, 1);
- if (SEM_FAILED == pSem1)
- {
- return -1;
- }
- sem_t *pSem2 = sem_open("bbb", O_CREAT, 0666, 0);
- if (SEM_FAILED == pSem2)
- {
- sem_close(pSem1);
- return -1;
- }
- while(1)
- {
- sem_wait(pSem1);
- printf("hello\r\n");
- sleep(1);
- sem_post(pSem2);
- }
- }
sem_b.c
- #include <stdio.h>
- #include <fcntl.h> /* For O_* constants */
- #include <sys/stat.h> /* For mode constants */
- #include <semaphore.h>
- int main()
- {
- sem_t *pSem1 = sem_open("aaa", O_CREAT, 0666, 1);
- if (SEM_FAILED == pSem1)
- {
- return -1;
- }
- sem_t *pSem2 = sem_open("bbb", O_CREAT, 0666, 0);
- if (SEM_FAILED == pSem2)
- {
- sem_close(pSem1);
- return -1;
- }
- while(1)
- {
- sem_wait(pSem2);
- printf("world\r\n");
- sleep(1);
- sem_post(pSem1);
- }
- }
共享内存函数(shmget、shmat、shmdt、shmctl
共享内存函数由shmget、shmat、shmdt、shmctl四个函数组成。下面的表格列出了这四个函数的函数原型及其具体说明。
1. shmget函数原型
shmget(得到一个共享内存标识符或创建一个共享内存对象)
所需头文件
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/ipc.h>
函数说明
得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符
函数原型
int shmget(key_t key, size_t size, int shmflg)
函数传入值
key
0(IPC_PRIVATE):会建立新共享内存对象
大于0的32位整数:视参数shmflg来确定操作。通常要求此值来源于ftok返回的IPC键值
size
大于0的整数:新建的共享内存大小,以字节为单位
0:只获取共享内存时指定为0
shmflg
0:取共享内存标识符,若不存在则函数会报错
IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个消息队列;如果存在这样的共享内存则报错
函数返回值
成功:返回共享内存的标识符
出错:-1,错误原因存于error中
附加说明
上述shmflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限
错误代码
EINVAL:参数size小于SHMMIN或大于SHMMAX
EEXIST:预建立key所指的共享内存,但已经存在
EIDRM:参数key所指的共享内存已经删除
ENOSPC:超过了系统允许建立的共享内存的最大值(SHMALL)
ENOENT:参数key所指的共享内存不存在,而参数shmflg未设IPC_CREAT位
EACCES:没有权限
ENOMEM:核心内存不足
在Linux环境中,对开始申请的共享内存空间进行了初始化,初始值为0x00。
如果用shmget创建了一个新的消息队列对象时,则shmid_ds结构成员变量的值设置如下:
Ÿ shm_lpid
、shm_nattach
、shm_atime、shm_dtime
设置为0。
Ÿ msg_ctime设置为当前时间。
Ÿ shm_segsz
设成创建共享内存的大小。
Ÿ shmflg的读写权限放在shm_perm.mode中。
Ÿ shm_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
2. shmat函数原型
shmat(把共享内存区对象映射到调用进程的地址空间)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
#include<sys/ipc.h>
函数说明
连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问
函数原型
void *shmat(int shmid, const void *shmaddr, int shmflg)
函数传入值
shmid
共享内存标识符
shmaddr
指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
shmflg
SHM_RDONLY:为只读模式,其他为读写模式
函数返回值
成功:附加好的共享内存地址
出错:-1,错误原因存于error中
附加说明
fork后子进程继承已连接的共享内存地址。exec后该子进程与已连接的共享内存地址自动脱离(detach)。进程结束后,已连接的共享内存地址会自动脱离(detach)
错误代码
EACCES:无权限以指定方式连接共享内存
EINVAL:无效的参数shmid或shmaddr
ENOMEM:核心内存不足
3. shmdt函数原型
shmat(断开共享内存连接)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
#includ<sys/ipc.h>
函数说明
与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存
函数原型
int shmdt(const void *shmaddr)
函数传入值
shmaddr:连接的共享内存的起始地址
函数返回值
成功:0
出错:-1,错误原因存于error中
附加说明
本函数调用并不删除所指定的共享内存区,而只是将先前用shmat函数连接(attach)好的共享内存脱离(detach)目前的进程
错误代码
EINVAL:无效的参数shmaddr
4. shmctl函数原型
shmctl(共享内存管理)
所需头文件
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
函数说明
完成对共享内存的控制
函数原型
int shmctl(int shmid, int cmd, struct shmid_ds *buf)
函数传入值
shmid
共享内存标识符
cmd
IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中
IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内
IPC_RMID:删除这片共享内存
buf
共享内存管理结构体。具体说明参见共享内存内核结构定义部分
函数返回值
成功:0
出错:-1,错误原因存于error中
错误代码
EACCESS:参数cmd为IPC_STAT,确无权限读取该共享内存
EFAULT:参数buf指向无效的内存地址
EIDRM:标识符为msqid的共享内存已被删除
EINVAL:无效的参数cmd或shmid
EPERM:参数cmd为IPC_SET或IPC_RMID,却无足够的权限执行
共享内存应用范例
5. 父子进程通信范例
父子进程通信范例,shm.c源代码如下:
- #include <stdio.h>
- #include <unistd.h>
- #include <string.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <error.h>
- #define SIZE 1024
- int main()
- {
- int shmid ;
- char *shmaddr ;
- struct shmid_ds buf ;
- int flag = 0 ;
- int pid ;
- shmid = shmget(IPC_PRIVATE, SIZE, IPC_CREAT|0600 ) ;
- if ( shmid < 0 )
- {
- perror("get shm ipc_id error") ;
- return -1 ;
- }
- pid = fork() ;
- if ( pid == 0 )
- {
- shmaddr = (char *)shmat( shmid, NULL, 0 ) ;
- if ( (int)shmaddr == -1 )
- {
- perror("shmat addr error") ;
- return -1 ;
- }
- strcpy( shmaddr, "Hi, I am child process!\n") ;
- shmdt( shmaddr ) ;
- return 0;
- } else if ( pid > 0) {
- sleep(3 ) ;
- flag = shmctl( shmid, IPC_STAT, &buf) ;
- if ( flag == -1 )
- {
- perror("shmctl shm error") ;
- return -1 ;
- }
- printf("shm_segsz =%d bytes\n", buf.shm_segsz ) ;
- printf("parent pid=%d, shm_cpid = %d \n", getpid(), buf.shm_cpid ) ;
- printf("chlid pid=%d, shm_lpid = %d \n",pid , buf.shm_lpid ) ;
- shmaddr = (char *) shmat(shmid, NULL, 0 ) ;
- if ( (int)shmaddr == -1 )
- {
- perror("shmat addr error") ;
- return -1 ;
- }
- printf("%s", shmaddr) ;
- shmdt( shmaddr ) ;
- shmctl(shmid, IPC_RMID, NULL) ;
- }else{
- perror("fork error") ;
- shmctl(shmid, IPC_RMID, NULL) ;
- }
- return 0 ;
- }
编译 gcc shm.c –o shm。
执行 ./shm,执行结果如下:
shm_segsz =1024 bytes
shm_cpid = 9503
shm_lpid = 9504
Hi, I am child process!
6. 多进程读写范例
多进程读写即一个进程写共享内存,一个或多个进程读共享内存。下面的例子实现的是一个进程写共享内存,一个进程读共享内存。
(1)下面程序实现了创建共享内存,并写入消息。
shmwrite.c源代码如下:
- #include <stdio.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- typedef struct{
- char name[8];
- int age;
- } people;
- int main(int argc, char** argv)
- {
- int shm_id,i;
- key_t key;
- char temp[8];
- people *p_map;
- char pathname[30] ;
- strcpy(pathname,"/tmp") ;
- key = ftok(pathname,0x03);
- if(key==-1)
- {
- perror("ftok error");
- return -1;
- }
- printf("key=%d\n",key) ;
- shm_id=shmget(key,4096,IPC_CREAT|IPC_EXCL|0600);
- if(shm_id==-1)
- {
- perror("shmget error");
- return -1;
- }
- printf("shm_id=%d\n", shm_id) ;
- p_map=(people*)shmat(shm_id,NULL,0);
- memset(temp, 0x00, sizeof(temp)) ;
- strcpy(temp,"test") ;
- temp[4]='0';
- for(i = 0;i<3;i++)
- {
- temp[4]+=1;
- strncpy((p_map+i)->name,temp,5);
- (p_map+i)->age=0+i;
- }
- shmdt(p_map) ;
- return 0 ;
- }
(2)下面程序实现从共享内存读消息。
shmread.c源代码如下:
- #include <stdio.h>
- #include <string.h>
- #include <sys/ipc.h>
- #include <sys/shm.h>
- #include <sys/types.h>
- #include <unistd.h>
- typedef struct{
- char name[8];
- int age;
- } people;
- int main(int argc, char** argv)
- {
- int shm_id,i;
- key_t key;
- people *p_map;
- char pathname[30] ;
- strcpy(pathname,"/tmp") ;
- key = ftok(pathname,0x03);
- if(key == -1)
- {
- perror("ftok error");
- return -1;
- }
- printf("key=%d\n", key) ;
- shm_id = shmget(key,0, 0);
- if(shm_id == -1)
- {
- perror("shmget error");
- return -1;
- }
- printf("shm_id=%d\n", shm_id) ;
- p_map = (people*)shmat(shm_id,NULL,0);
- for(i = 0;i<3;i++)
- {
- printf( "name:%s\n",(*(p_map+i)).name );
- printf( "age %d\n",(*(p_map+i)).age );
- }
- if(shmdt(p_map) == -1)
- {
- perror("detach error");
- return -1;
- }
- return 0 ;
- }
(3)编译与执行
① 编译gcc shmwrite.c -o shmwrite。
② 执行./shmwrite,执行结果如下:
key=50453281
shm_id=688137
③ 编译gcc shmread.c -o shmread。
④ 执行./shmread,执行结果如下:
key=50453281
shm_id=688137
name:test1
age 0
name:test2
age 1
name:test3
age 2
⑤ 再执行./shmwrite,执行结果如下:
key=50453281
shmget error: File exists
⑥ 使用ipcrm -m 688137删除此共享内存。
1. 信号概念
信号是进程在运行过程中,由自身产生或由进程外部发过来的消息(事件)。信号是硬件中断的软件模拟(软中断)。每个信号用一个整型常量宏表示,以SIG开头,比如SIGCHLD、SIGINT等,它们在系统头文件中定义,也可以通过在shell下键入kill –l查看信号列表,或者键入man 7 signal查看更详细的说明。
信号的生成来自内核,让内核生成信号的请求来自3个地方:
l 用户:用户能够通过输入CTRL+c、Ctrl+\,或者是终端驱动程序分配给信号控制字符的其他任何键来请求内核产生信号;
l 内核:当进程执行出错时,内核会给进程发送一个信号,例如非法段存取(内存访问违规)、浮点数溢出等;
l 进程:一个进程可以通过系统调用kill给另一个进程发送信号,一个进程可以通过信号和另外一个进程进行通信。
由进程的某个操作产生的信号称为同步信号(synchronous signals),例如除0;由象用户击键这样的进程外部事件产生的信号叫做异步信号。(asynchronous signals)。
进程接收到信号以后,可以有如下3种选择进行处理:
l 接收默认处理:接收默认处理的进程通常会导致进程本身消亡。例如连接到终端的进程,用户按下CTRL+c,将导致内核向进程发送一个SIGINT的信号,进程如果不对该信号做特殊的处理,系统将采用默认的方式处理该信号,即终止进程的执行;
l 忽略信号:进程可以通过代码,显示地忽略某个信号的处理,例如:signal(SIGINT,SIGDEF);但是某些信号是不能被忽略的,
l 捕捉信号并处理:进程可以事先注册信号处理函数,当接收到信号时,由信号处理函数自动捕捉并且处理信号。
有两个信号既不能被忽略也不能被捕捉,它们是SIGKILL和SIGSTOP。即进程接收到这两个信号后,只能接受系统的默认处理,即终止线程。
2. signal信号处理机制
可以用函数signal注册一个信号捕捉函数。原型为:
#include
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
signal 的第1个参数signum表示要捕捉的信号,第2个参数是个函数指针,表示要对该信号进行捕捉的函数,该参数也可以是SIG_DEF(表示交由系统缺省处理,相当于白注册了)或SIG_IGN(表示忽略掉该信号而不做任何处理)。signal如果调用成功,返回以前该信号的处理函数的地址,否则返回 SIG_ERR。
sighandler_t是信号捕捉函数,由signal函数注册,注册以后,在整个进程运行过程中均有效,并且对不同的信号可以注册同一个信号捕捉函数。该函数只有一个参数,表示信号值。
示例:
1、 捕捉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
void SignHandler(int iSignNo)
{
printf("Capture sign no:%d/n",iSignNo);
}
int main()
{
signal(SIGINT,SignHandler);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,通过按 CTRL+c将不再终止程序的运行。应为CTRL+c产生的SIGINT信号已经由进程中注册的SignHandler函数捕捉了。该程序可以通过 Ctrl+/终止,因为组合键Ctrl+/能够产生SIGQUIT信号,而该信号的捕捉函数尚未在程序中注册。
2、 忽略掉终端CTRL+c产生的SIGINT信号:
#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
#include <sys/types.h>
int main()
{
signal(SIGINT,SIG_IGN);
while(true)
sleep(1);
return 0;
}
该程序运行起来以后,将CTRL+C产生的SIGINT信号忽略掉了,所以CTRL+C将不再能是该进程终止,要终止该进程,可以向进程发送SIGQUIT信号,即组合键CTRL+/
3、 接受信号的默认处理,接受默认处理就相当于没有写信号处理程序:
- #include <unistd.h>
- #include <stdio.h>
- #include <sys/wait.h>
- #include <sys/types.h>
- int main()
- {
- signal(SIGINT,DEF);
- while(true)
- sleep(1);
- return 0;
- }
3.1. 信号处理情况分析
在signal处理机制下,还有许多特殊情况需要考虑:
1、 册一个信号处理函数,并且处理完毕一个信号之后,是否需要重新注册,才能够捕捉下一个信号;
2、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个同类型的信号,这时该怎么处理;
3、 如果信号处理函数正在处理信号,并且还没有处理完毕时,又发生了一个不同类型的信号,这时该怎么处理;
4、 如果程序阻塞在一个系统调用(如read(...))时,发生了一个信号,这时是让系统调用返回错误再接着进入信号处理函数,还是先跳转到信号处理函数,等信号处理完毕后,系统调用再返回。
示例:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <signal.h>
- int g_iSeq=0;
- void SignHandler(int iSignNo)
- {
- int iSeq=g_iSeq++;
- printf("%d Enter SignHandler,signo:%d./n",iSeq,iSignNo);
- sleep(3);
- printf("%d Leave SignHandler,signo:%d/n",iSeq,iSignNo);
- }
- int main()
- {
- char szBuf[8];
- int iRet;
- signal(SIGINT,SignHandler);
- signal(SIGQUIT,SignHandler);
- do{
- iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
- if(iRet<0){
- perror("read fail.");
- break;
- }
- szBuf[iRet]=0;
- printf("Get: %s",szBuf);
- }while(strcmp(szBuf,"quit/n")!=0);
- return 0;
- }
1、 CTRL+c] [CTRL+c] [CTRL+c]
2、 [CTRL+c] [CTRL+/]
3、 hello [CTRL+/] [Enter]
4、 [CTRL+/] hello [Enter]
5、 hel [CTRL+/] lo[Enter]
针对于上面各种情况,不同版本OS可能有不同的响应结果。
3.2. sigaction信号处理注册
如果要想用程序控制上述各种情况的响应结果,就必须采用新的信号捕获机制,即使用sigaction信号处理机制。
函数原型:
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
sigaction也用于注册一个信号处理函数。
参数signum为需要捕捉的信号;
参数 act是一个结构体,里面包含信号处理函数地址、处理方式等信息。
参数oldact是一个传出参数,sigaction函数调用成功后,oldact里面包含以前对signum的处理方式的信息。
如果函数调用成功,将返回0,否则返回-1
结构体 struct sigaction(注意名称与函数sigaction相同)的原型为:
struct sigaction {
void (*sa_handler)(int); // 老类型的信号处理函数指针
void (*sa_sigaction)(int, siginfo_t *, void *);//新类型的信号处理函数指针
sigset_t sa_mask; // 将要被阻塞的信号集合
int sa_flags; // 信号处理方式掩码
void (*sa_restorer)(void); // 保留,不要使用。
}
该结构体的各字段含义及使用方式:
1、字段sa_handler是一个函数指针,用于指向原型为void handler(int)的信号处理函数地址, 即老类型 的信号处理函数;
2、字段sa_sigaction也是一个函数指针,用于指向原型为:
void handler(int iSignNum,siginfo_t *pSignInfo,void *pReserved);
的信号处理函数,即新类型的信号处理函数。
该函数的三个参数含义为:
iSignNum :传入的信号
pSignInfo :与该信号相关的一些信息,它是个结构体
pReserved :保留,现没用
3、字段sa_handler和sa_sigaction只应该有一个生效,如果想采用老的信号处理机制,就应该让sa_handler指向正确的信号处理函数;否则应该让sa_sigaction指向正确的信号处理函数,并且让字段 sa_flags包含SA_SIGINFO选项。
4、字段sa_mask是一个包含信号集合的结构体,该结构体内的信号表示在进行信号处理时,将要被阻塞的信号。针对sigset_t结构体,有一组专门的函数对它进行处理,它们是:
#include <signal.h>
int sigemptyset(sigset_t *set); // 清空信号集合set
int sigfillset(sigset_t *set); // 将所有信号填充进set中
int sigaddset(sigset_t *set, int signum); // 往set中添加信号signum
int sigdelset(sigset_t *set, int signum); // 从set中移除信号signum
int sigismember(const sigset_t *set, int signum); // 判断signnum是不是包含在set中
例如,如果打算在处理信号SIGINT时,只阻塞对SIGQUIT信号的处理,可以用如下种方法:
struct sigaction act;
sigemptyset(&act.sa_mask);
sigaddset(&act_sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL);
5、 字段sa_flags是一组掩码的合成值,指示信号处理时所应该采取的一些行为,各掩码的含义为:
掩码 描述
SA_RESETHAND 处理完毕要捕捉的信号后,将自动撤消信号处理函数的注册,即必须再重新注册信号处理函数,才能继续处理接下来产生的信号。该选项不符合一般的信号处理流程,现已经被废弃。
SA_NODEFER 在处理信号时,如果又发生了其它的信号,则立即进入其它信号的处理,等其它信号处理完毕后,再继续处理当前的信号,即递规地处理。如果sa_flags包含了该掩码,则结构体sigaction的sa_mask将无效!
SA_RESTART 如果在发生信号时,程序正阻塞在某个系统调用,例如调用read()函数,则在处理完毕信号后,接着从阻塞的系统返回。该掩码符合普通的程序处理流程,所以一般来说,应该设置该掩码,否则信号处理完后,阻塞的系统调用将会返回失败!
SA_SIGINFO 指示结构体的信号处理函数指针是哪个有效,如果sa_flags包含该掩码,则sa_sigactiion指针有效,否则是sa_handler指针有效。
练习与验证:
针对于先前的5种输入情况,给下面代码再添加一些代码,使之能够进行如下各种形式的响应:
1 、[CTRL+c] [CTRL+c]时,第1个信号处理阻塞第2个信号处理;
2 、[CTRL+c] [CTRL+c]时,第1个信号处理时,允许递规地第2个信号处理;
3 、[CTRL+c] [CTRL+/]时,第1个信号阻塞第2个信号处理;
4 、read不要因为信号处理而返回失败结果。
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <signal.h>
- int g_iSeq=0;
- void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
- {
- int iSeq=g_iSeq++;
- printf("%d Enter SignHandlerNew,signo:%d./n",iSeq,iSignNo);
- sleep(3);
- printf("%d Leave SignHandlerNew,signo:%d/n",iSeq,iSignNo);
- }
- int main()
- {
- char szBuf[8];
- int iRet;
- struct sigaction act;
- act.sa_sigaction=SignHandlerNew;
- act.sa_flags=SA_SIGINFO;
- //
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
- sigaction(SIGQUIT,&act,NULL);
- do{
- iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
- if(iRet<0){
- perror("read fail.");
- break;
- }
- szBuf[iRet]=0;
- printf("Get: %s",szBuf);
- }while(strcmp(szBuf,"quit/n")!=0);
- return 0;
- }
3.3. sigprocmask信号阻塞
函数sigaction中设置的被阻塞信号集合只是针对于要处理的信号,例如
struct sigaction act;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask,SIGQUIT);
sigaction(SIGINT,&act,NULL);
表示只有在处理信号SIGINT时,才阻塞信号SIGQUIT;
函数sigprocmask是全程阻塞,在sigprocmask中设置了阻塞集合后,被阻塞的信号将不能再被信号处理函数捕捉,直到重新设置阻塞信号集合。
原型为:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
参数how的值为如下3者之一:
a :SIG_BLOCK ,将参数2的信号集合添加到进程原有的阻塞信号集合中
b :SIG_UNBLOCK ,从进程原有的阻塞信号集合移除参数2中包含的信号
c :SIG_SET,重新设置进程的阻塞信号集为参数2的信号集
参数set为阻塞信号集
参数oldset是传出参数,存放进程原有的信号集。
示例:
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <signal.h>
- int g_iSeq=0;
- void SignHandlerNew(int iSignNo,siginfo_t *pInfo,void *pReserved)
- {
- int iSeq=g_iSeq++;
- printf("%d Enter SignHandlerNew,signo:%d./n",iSeq,iSignNo);
- sleep(3);
- printf("%d Leave SignHandlerNew,signo:%d/n",iSeq,iSignNo);
- }
- int main()
- {
- char szBuf[8];
- int iRet;
- struct sigaction act;
- act.sa_sigaction=SignHandlerNew;
- act.sa_flags=SA_SIGINFO;
- // 屏蔽掉SIGINT 信号,SigHandlerNew 将不能再捕捉SIGINT
- sigset_t sigSet;
- sigemptyset(&sigSet);
- sigaddset(&sigSet,SIGINT);
- sigprocmask(SIG_BLOCK,&sigSet,NULL);
- //
- sigemptyset(&act.sa_mask);
- sigaction(SIGINT,&act,NULL);
- sigaction(SIGQUIT,&act,NULL);
- do{
- iRet=read(STDIN_FILENO,szBuf,sizeof(szBuf)-1);
- if(iRet<0){
- perror("read fail.");
- break;
- }
- szBuf[iRet]=0;
- printf("Get: %s",szBuf);
- }while(strcmp(szBuf,"quit/n")!=0);
- return 0;
- }
4. 用程序发送信号
4.1. kill信号发送函数
原型为:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
参数pid为将要接受信号的进程的pid
参数sig为要发送的信号
如果成功,返回0,否则为-1。
示例,输入结束后,将通过发送信号SIGQUIT把自己杀掉:
- #include <stdio.h>
- #include <signal.h>
- #include <unistd.h>
- #include <sys/types.h>
- int main()
- {
- while(true){
- if(getchar()==EOF)
- kill(getpid(),SIGQUIT);
- }
- return 0;
- }
sigqueue也可以发送信号,并且能传递附加的信息。
原型为:
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
参数pid为接收信号的进程;
参数sig为要发送的信号;
参数value为一整型与指针类型的联合体:
union sigval {
int sival_int;
void *sival_ptr;
};
由sigqueue函数发送的信号的第3个参数value的值,可以被进程的信号处理函数的第2个参数info->si_ptr接收到。
示例1,进程给自己发信号,并且带上附加信息:
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- void SignHandlerNew(int signum,siginfo_t *info,void *myact)
- {
- char *pszInfo=(char *)(info->si_ptr);
- printf("Get:%d info:%s/n",signum,pszInfo);
- }
- int main(int argc,char**argv)
- {
- struct sigaction act;
- union sigval mysigval;
- int sig;
- char data[]="other info";
- //
- if(argc<2){
- printf("usage: SIGNNUM/n");
- return -1;
- }
- mysigval.sival_ptr=data;
- sig=atoi(argv[1]);
- sigemptyset(&act.sa_mask);
- act.sa_sigaction=SignHandlerNew;
- act.sa_flags=SA_SIGINFO;
- sigaction(sig,&act,NULL);
- while(true){
- printf("wait for the signal/n");
- sigqueue(getpid(),sig,mysigval);
- sleep(2);
- }
- }
示例2:一个进程向另外一个进程发送信号。注意:发送进程不要将自己进程空间的地址发送给接收进程,因为接收进程接收到地址也访问不到发送进程的地址空间的。
示例2信号接收程序:
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- void SignHandlerNew(int signum,siginfo_t *info,void *myact)
- {
- printf("Get:%d info:%d/n",signum,info->si_int);
- }
- int main(int argc,char**argv)
- {
- struct sigaction act;
- //
- if(argc<2){
- printf("usage: signnum/n");
- return -1;
- }
- sigemptyset(&act.sa_mask);
- act.sa_sigaction=SignHandlerNew;
- act.sa_flags=SA_SIGINFO;
- sigaction(atoi(argv[1]),&act,NULL);
- while(1)
- {
- printf("wait for the signal/n");
- sleep(2);
- }
- return 0;
- }
示例2信号发送程序:
- #include <signal.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- int main(int argc,char**argv)
- {
- union sigval mysigval;
- int iPid,iSignNo,iData;
- //
- if(argc<4){
- printf("usage: pid signnum data/n");
- return -1;
- }
- iPid=atoi(argv[1]);
- iSignNo=atoi(argv[2]);
- iData=atoi(argv[3]);
- mysigval.sival_int=iData;
- if(sigqueue(iPid,iSignNo,mysigval)<0)
- perror("Send signal fail.");
- return 0;
- }
5. 计时器与信号
5.1. 睡眠函数
Linux下有两个睡眠函数,原型为:
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
void usleep(unsigned long usec);
函数sleep让进程睡眠seconds秒,函数usleep让进程睡眠usec毫秒。
sleep 睡眠函数内部是用信号机制进行处理的,用到的函数有:
#include <unistd.h>
unsigned int alarm(unsigned int seconds); // 告知自身进程,要进程在seconds秒后自动产生一个//SIGALRM的信号,
int pause(void); // 将自身进程挂起,直到有信号发生时才从pause返回
示例:模拟睡眠3秒:
- #include <signal.h>
- #include <stdio.h>
- #include <unistd.h>
- void SignHandler(int iSignNo)
- {
- printf("signal:%d/n",iSignNo);
- }
- int main()
- {
- signal(SIGALRM,SignHandler);
- alarm(3);
- printf("Before pause()./n");
- pause();
- printf("After pause()./n");
- return 0;
- }
5.2. 时钟处理
Linux为每个进程维护3个计时器,分别是真实计时器、虚拟计时器和实用计时器。
l 真实计时器计算的是程序运行的实际时间;
l 虚拟计时器计算的是程序运行在用户态时所消耗的时间(可认为是实际时间减掉(系统调用和程序睡眠所消耗)的时间);
l 实用计时器计算的是程序处于用户态和处于内核态所消耗的时间之和。
例如:有一程序运行,在用户态运行了5秒,在内核态运行了6秒,还睡眠了7秒,则真实计算器计算的结果是18秒,虚拟计时器计算的是5秒,实用计时器计算的是11秒。
用指定的初始间隔和重复间隔时间为进程设定好一个计时器后,该计时器就会定时地向进程发送时钟信号。3个计时器发送的时钟信号分别为:SIGALRM,SIGVTALRM和SIGPROF。
用到的函数与数据结构:
#include <sys/time.h>
//获取计时器的设置
//which指定哪个计时器,可选项为ITIMER_REAL(真实计时器)、ITIMER_VITUAL(虚拟计时器、ITIMER_PROF(实用计时器))
//value为一结构体的传出参数,用于传出该计时器的初始间隔时间和重复间隔时间
//如果成功,返回0,否则-1
int getitimer(int which, struct itimerval *value);
//设置计时器
//which指定哪个计时器,可选项为ITIMER_REAL(真实计时器)、ITIMER_VITUAL(虚拟计时器、ITIMER_PROF(实用计时器))
//value为一结构体的传入参数,指定该计时器的初始间隔时间和重复间隔时间
//ovalue为一结构体传出参数,用于传出以前的计时器时间设置。
//如果成功,返回0,否则-1
int setitimer(int which, const struct itimerval *value, struct itimer val *ovalue);
struct itimerval {
struct timeval it_interval; /* next value */ // 重复间隔
struct timeval it_value; /* current value */ // 初始间隔
};
struct timeval {
long tv_sec; /* seconds */ // 时间的秒数部分
long tv_usec; /* microseconds */ // 时间的微秒部分
};
示例:启用真实计时器的进行时钟处理
- #include <stdio.h>
- #include <unistd.h>
- #include <signal.h>
- #include <sys/time.h>
- void TimeInt2Obj(int imSecond,timeval *ptVal)
- {
- ptVal->tv_sec=imSecond/1000;
- ptVal->tv_usec=(imSecond%1000)*1000;
- }
- void SignHandler(int SignNo)
- {
- printf("Clock/n");
- }
- int main()
- {
- signal(SIGALRM,SignHandler);
- itimerval tval;
- TimeInt2Obj(1,&tval.it_value); // 设初始间隔为1毫秒,注意不要为0
- TimeInt2Obj(1500,&tval.it_interval); // 设置以后的重复间隔为1500毫秒
- setitimer(ITIMER_REAL,&tval,NULL);
- while(getchar()!=EOF);
- return 0;
- }
SIGHUP 终止进程 终端线路挂断
SIGINT 终止进程 中断进程
SIGQUIT 建立CORE文件终止进程,并且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟踪自陷
SIGBUS 建立CORE文件 总线错误
SIGSEGV 建立CORE文件 段非法错误
SIGFPE 建立CORE文件 浮点异常
SIGIOT 建立CORE文件 执行I/O自陷
SIGKILL 终止进程 杀死进程
SIGPIPE 终止进程 向一个没有读进程的管道写数据
SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号
SIGSTOP 停止进程 非终端来的停止信号
SIGTSTP 停止进程 终端来的停止信号
SIGCONT 忽略信号 继续执行一个停止的进程
SIGURG 忽略信号 I/O紧急信号
SIGIO 忽略信号 描述符上可以进行I/O
SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
SIGTTOU 停止进程 后台进程写终端
SIGTTIN 停止进程 后台进程读终端
SIGXGPU 终止进程 CPU时限超时
SIGXFSZ 终止进程 文件长度过长
SIGWINCH 忽略信号 窗口大小发生变化
SIGPROF 终止进程 统计分布图用计时器到时
SIGUSR1 终止进程 用户定义信号1
SIGUSR2 终止进程 用户定义信号2
SIGVTALRM 终止进程 虚拟计时器到时
- 进程线程
- 线程 & 进程
- 进程/线程
- 进程|线程
- 进程&线程
- 进程 线程
- 进程、线程
- 进程--线程
- 线程 、 进程
- 进程,线程
- 线程、进程
- 进程 线程
- 进程、线程
- 线程,进程
- 进程线程
- 进程,线程
- 进程 & 线程
- 进程、线程
- 234. Palindrome Linked List
- 初学数据结构---理清数据结构名称
- 多路IOepoll模型
- 理解HashMap
- IOS 从小工到专家(必看)
- 进程线程
- 解决Django 提交表单时403错误:CSRF verification failed. Request aborted .
- 数据查询--参数化查询
- 教你轻松记住js正则表达式
- Leetcode--65. Valid Number
- 拉勾网招聘数据分析
- 常见对象_模拟用户登录案例
- 码出你的第一个Django app——Django官方教程(一)
- Method方法小结