精华内容
下载资源
问答
  • 概念:信号是UNIX和Linux系统响应某些条件而产生的事件,信号提供了一种处理异步事件的方法,信号是由于某些错误条件产生的,例如内存段错误、浮点处理器错误、非法指令等。 处理信号的三种方式: 忽略此信号。...

    信号机制及其使用

    概念:信号是UNIX和Linux系统响应某些条件而产生的事件,信号提供了一种处理异步事件的方法,信号是由于某些错误条件产生的,例如内存段错误、浮点处理器错误、非法指令等。
    处理信号的三种方式:
    忽略此信号。大多数信号都可以被忽略,但是SIGKILL和SIGSTOP这两种信号不可以被忽略,原因:它是超级用户终止进程的可靠方法,
    捕获信号,在某种信号发生的时候需要调用用户函数,在用户函数中对这种事件的处理,例如:SIGCHLD信号标识是子进程结束,所以可以捕获此信号调用waitpid获取子进程的ID和终止状态。
    默认,系统会对信号作出默认动作,大部分为终止进程。
    信号的使用:
      signal函数:

    void (*signal (int sig, void (*func) (int))) (int);
    singnal函数说明粗函数需要两个参数,返回一个函数指针,而该指针所指向的函数无返回值(void),第一个参数sig是一个整数,准备捕获或忽略的信号,第二个参数是一个函数指针,它指向的函数需要一个整形参数,无返回值,signal函数的返回值是一个函数地址,该函数有一个整形参数。

    可重入函数:一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段代码,而返回控制时不会出现什么错误;而不可重入的函数由于使用了一些系统资源,比如全局变量区,中断向量表等,所以它如果被中断的话,可能会出现问题,这类函数是不能运行在多任务环境下的(多线程)。
    保证函数可重入方法:
    函数中尽量使用局部变量(寄存器、堆、栈)
    操作全局变量要加以保护(信号量、锁等),这样构成的函数是可重入的。

    发送信号:
    kill函数将信号发送给进程或者进程组,raise函数则允许进程想自身发送信号。

    		int kill(pid_t pid, int sig); 底层为sys_kill()
    		int raise(int sig);
    

    两者之间的关系 raise(sig) == kill(getpid(), sig)
    kill函数的pid参数四种情况
      pid>0 发送信号到指定进程的pid
      pid=0 将信号发送给当前进程组的所有进程
      pid=-1 发送信号给除第一个进程外的所有进程(权限所能发送的进程,权限不足则无法发送)
      pid<0 发送信号给进程组ID为|pid|的所有进程

    进程间通讯

    管道
    概念:类似于现实中管道一样进程的数据从一端流向另一端,即一端进行写操作,另一端执行读操作,也导致管道是半双工通讯。若管道为空,read会阻塞,若管道满,则write会阻塞。
    有名管道&无名管道:
    有名管道:可以再任意进程之间进行通讯,而且是双向的,但同一时间仅能一端读一端写。
    无名管道:只能在有亲缘关系的进程中使用并且是单向的,只能一端读,另一端写。
    管道符合先进先出的原则。
    编程实例:
    有名管道

    //write
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    #include<fcntl.h>
    int main()
    {
    	int fd = open("./FIFO", O_WRONLY);
    	assert(fd != -1);
    	printf("FOFO open success\n");
    	while(1)
    	{
    		char buff[128] = {0};
    		printf("please input: ");
    		scanf("%s", buff);
    		write(fd, buff, strlen(buff));
    		if(strncmp(buff, "end", 3) == 0)
    		{
    			break;
    		}
    	}
    	close(fd);
    	exit(0);
    }
    //read
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    #include<fcntl.h>
    int main()
    {
    	int fd = open("./FIFO", O_RDONLY);
    	assert(fd != -1);
    
    printf("open FIFO success\n");
    
    while(1)
    	{
    		char buff[128] = {0};
    		int n = read(fd, buff, 127);
    
    if(n == 0 || (n == 3 && strncmp(buff, "end", 3) == 0))
    		{
    			break;
    		}
    		int i = 0;
    		while(i <strlen(buff))
    		{
    			printf("%d", buff[i++]);
    		}
    		printf("\n");
    	}
    	close(fd);
    	exit(0);
    }
    

    无名管道

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    
    int main()
    {
    	itn fds[2] = {-1, -1};
    	//pipe必须在fork之前调用,创建无名管道fd[0]为read,fd[1]为write
    	int res = pipe(fds);
    	assert(res != -1);
    
    pid_t n = fork();
    	assert(n != -1);
    
    if(n == 0)
    	{
    		close(fds[1]);//仅仅读取数据,所以关闭写端
    		while(1)
    		{
    			char buff[128] = {0};
    			int n = read(fds[0], buff, 127);
    			if(n<=0 || 0 == strncmp(buff, "end", 3))
    			{
    				break;
    			}
    			printf("child: %s\n", buff);
    		}
    		close(fds[0]);
    	}
    	else
    	{
    		close(fds[0]);
    		while(1)
    		{
    			printf("please input: ");
    			char buff[128] = {0};
    			fgets(buff, 128, stdin);
    
    write(fd[1], buff, strlen(buff)-1);
    			if(strncmp(buff, "end", 3) == 0)
    			{
    				break;
    			}
    		}
    		close(fds[1]);
    	}
    }
    

    消息队列
    概念:消息队列时消息的链表,有特定的格式,存放在内存当中,有消息队列标识符标识;消息队列允许一个或多个进程向他写入与读取消息;消息队列可以实现消息的随机查询,不一定先进先出,可以按照类型读取。
    消息队列的使用
      msgget函数用来创建和访问一个消息队列。

       int msgget(key_t key, int msgflg);
       key是我们需要提供来命名消息队列的键值,msgflg是权限标志
      返回值:成功返回正整数,消息队列标识符,失败返回-1

      msgsnd函数用来将消息添加到消息队列。

      int msgsnd(int msqid, const void *msg_ptr, size_t msg_sz,> int msgflg);
      msqid是msgget函数返回的消息队列标识符,msg_ptr是一个指向准备发送消息的指针,msg_sz是msg_ptr指向的消息的长度,msgflg是控制消息队列满或者消息队列到达系统范围限制将要发生的事件。
      返回值:成功返回0,失败返回-1,若成功是将消息数据的一份副本存放到消息队列中。

      msgrcv函数是从一个消息队列获取消息

      int msgrcv(int msqid, void *msg_ptr, size_t msg_sz, long
    int msgtype, int msgflg);
      msqid是消息队列的标识符,msg_ptr是指向准备接受消息的指针,msg_sz是msg_ptr指向消息的长度,msgtype是实现消息队列的优先级,msgflg是控制消息队列满或者消息队列到达系统范围限制将要发生的事件。
      返回值:成功返回接收缓冲区的字节数,消息被分配到msg_ptr指向的用户缓存区,并删除对应的消息,失败返回-1。

      msgctl函数类似于共享内存的控制函数。

      int msgctl(itn msqid, int command, struct msqid_ds *buf);
      msqid是消息队列的标识符,command是要采取的动作。
      返回值:成功返回0,失败返回-1。

    编程实例:
    创建消息队列并将消息添加消息队列

    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<assert.h>
    #include<string.h>
    #include<sys/msg.h>
    
    typedef struct masgdata
    {
    	long mtype;
    	char mtext[128];
    }MsgData;
    
    int main()
    {
    	int msgid - msgget((key_t)1234, 0664|IPC_CREAT);
    	assert(msgid != -1);
    
    MsgData data;
    	meset(&data, 0, sizeof(data));
    	data.mtype = 100;
    	strcpy(data.mtext, "hello");
    
    msgsnd(msgid, &data, strlen(data,mtext, 0);
    meset(&data, 0, sizeof(data));
    	data.mtype = 200;
    	strcpy(data.mtext, "world");
    
    msgsnd(msgid, &data, strlen(data,mtext, 0);
    
    }
    

    获取消息队列中的消息

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <assert.h>
    #include <string.h>
    
    #include <sys/msg.h>
    typedef struct msgdata
    {
    	long mtype;
    	char mtext[128];
    }MsgData;
    int main()
    {
    	int msgid = msgget((key_t)1234, 0664|IPC_CREAT);
    	assert(msgid != -1);
    
    	MsgData data;
    
    	meset(&data, 0, sizeof(data));
    
    	msgrcv(msgid, &data, 127, 100, 0);//取出消息队列中符合标识的消息
    	printf("data.mtype:%d\n", data.mtype);
    	printf("data.mtext:%d\n", data.mtext);
    }
    

    信号量
    概念:用来同步进程的特殊变量,一个特殊的计数器,大于0时记录资源的数量,小于0时,记录等待资源的进程数量,当信号量的值大于0时,进程总是可以获取到资源并使用的,小于0时,进程必须阻塞等到其他进程释放资源。
    相关概念:
    临界资源:同一时刻只能被一个进程访问的资源。
    临界区:访问临界资源的代码区域。
    原子操作:不能被打断的操作,要么全部完成,要不一个都不做。
    P、V操作:P操作临界资源-1,V操作临界资源+1。

      信号量操作:
    1.创建或者获取信号量

    int semget((key_t)key, int nsems, int flag);
    key可以让不相关的进程访问同一个信号量,先是提供一个键,然后在由系统产生一个相应的信号量标识,nsems是该集合中信号量数,若是新创建的信号量则须指定nsems,若是引用现有的集合则将nsems指定为0。
    int semctl(int semid, int semnum, int cmd, /*union semun arg */)
    cmd是10种命令的一种,在semid指定的信号量集合执行命令(SETVAL) Union semun { int
    val; struct semid_ds *buf; unsigned short *array; }
    arg.val指的是信号量的初始值

    2.P、V操作(都必须为原子操作)

    int semop(int semid, struct sembuf[], size_t size);
    struct sembuf
    {  short sem_num;//指定本变量操作的信号量集中信号量的下标
      short sem_op;//-1 P操作,+1 V操作
      short sem_flg;
    }
    3.释放内核对象 int semctl(int semid, int semnum, int cmd); 立即删除

    编程实例

    //sem.h
    #pragma once
    
    typedef union semun
    {
    	int val;
    }SemUn;
    
    int SemGet(int key, int initval[], int nsems);
    int SemP(int semid, int sems[], int len);
    int SemV(int semid, int sems[], int len);
    int SemDel(int semid);
    
    //sem.c
    #include<stdio.h>
    #include<malloc.h>
    #include<assert.h>
    #include<sys/sem.h>
    
    int SemGet(int key, int initvalp[], int nsems)
    {
    	int semid = semget((key_t)key, 0, 0664);
    	if(-1 == semid)//没有获取到信号量标识
    	{
    		semid = semget((key_t)key, nsem, 0664|IPC_CREAT);
    		if(-1 == semid)
    		{
    			perror("create sem fail");
    			return -1;
    		}
    		int i = 0;
    		for(;i<nsems;++i)
    		{
    			SemUn sem;
    			sem.val = initval[i];
    			semctl(semid, i, SETVAL, sem);
    		}
    	}
    	return semid;
    }
    int SemP(int semid, int sems[], int len)
    {
    	struct sembuf *buf = (struct sembuf*)malloc(sizeof(struct sembuf) * len);
    	assert(buf != NULL);
    
    	int i = 0;
    	for(; i<len; ++i)
    	{
    		buf[i].sem_num = sem[i];
    		buf[i].semop = -1;
    		buf[i].sem_flg = SEM_UNDO;
    	}
    	if(-1 == semop(semid, buf, len))
    	{
    		perror("P fail");
    		return -1;
    	}
    	free(buf);
    	return 0;
    }
    int SemV(int semid, int sems[], int len)
    {
    	struct sembuf *buf = (struct sembuf*)malloc(sizeof(struct sembuf) * len);
    	assert(buf != NULL);
    
    	int i = 0;
    	for(; i<len; ++i)
    	{
    		buf[i].sem_num = sem[i];
    		buf[i].semop = 1;
    		buf[i].sem_flg = SEM_UNDO;
    	}
    	if(-1 == semop(semid, buf, len))
    	{
    		perror("P fail");
    		return -1;
    	}
    	free(buf);
    	return 0;
    }
    int SemDel(int semid)
    {
    	if(-1 == semctl(semid, 0, IPC_RMID))
    	{
    		perror("Delete sem fail");
    		return -1;
    	}
    	return 0;
    }
    
    //SemA.c
    #include"sem.h"
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<assert.h>
    #include<fcntl.h>
    #include<string.h>
    
    int main()
    {
    	int sem =0;
    	int semid = SemGet(123, &sem, 1);
    	assert(semid != -1);
    
    	int fd = open("file.txt", O_WRONLY | O_CREAT, 0664);
    	assert(fd != -1);
    
    	while(1)
    	{
    		printf("please input: ");
    		char buff[128] = {0};
    		fgets(buff, 128, stdin);
    
    		if(strncmp(buff, "end", 3) == 0)
    		{
    			break;
    		}
    		write(fd, buff, strlen(buff)-1);
    	}
    	close(fd);
    	int index = 0;
    	SemV(semid, &index, 1);
    }
    
    //SemB.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<assert.h>
    #include<unistd.h>
    #include<fcntl.h>
    #include"sem.h"
    
    int main()
    {
    	int sem = 0;
    	int semid = SemGet(1234, &sem, 1);
    	assert(sem != -1);
    
    	int index = 0;
    	SemP(semid, &index, 1);
    
    	int fd = open("file.txt", O_RDONLY);
    	assert(fd != -1);
    
    	while(1)
    	{
    		char buff[128] = {0};
    		int n = read(fd, buff, 127);
    		if(n <= 0)
    		{
    			break;
    		}
    		printf("%s", buff);
    	}
    	printf("\n");
    	close(fd);
    }
    
    //实现父子进程交替打印
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    
    #include"sem.h"
    
    int main()
    {
    	int sem = 1;
    	int semid = SemGet(1234, &sem, 1);
    	assert(semid != -1);
    
    	pid_t pid = fork();
    	assert(pid != -1);
    
    	if(pid == 0)
    	{
    		int index = 0;
    		int i = 0;
    		for(; i<5; ++i)
    		{
    			SemP(semid, &index, 1);
    			printf("child\n");
    			sleep(1);
    			SemV(semid, &index, 1);
    		}
    	}
    	else
    	{
    		int index = 0;
    		int i = 0;
    		for(; i<5;++i)
    		{
    			SemP(semid, &index, 1);
    			printf("father\n");
    			sleep(1);
    			SemV(semid, &index, 1);
    		}
    	}
    }
    

    共享内存
    概念:多个进程共享一块物理内存地址,只是将这块物理内存映射到自己的虚拟空间地址,因此共享内存是进程间通信最快的的方式,但是进程之间必须做同步控制。
    共享内存的使用:
    1.创建共享内存

    int shmget(key_t key, size_t size, int shmflg);
    key为共享内存命名,size以字节为单位指定共享内存容量,shmflg权限标志。

    2.启用对一个创建的共享内存的访问

    void *shmat(int shm_id, const void *shm_addr, int shmflg);
    shm_id是共享内存的标识符,shm_addr是共享内存连接到当前进程中的地址位置,一般为NULL,让系统指定,shmflg是一组位标志,若成功则返回一个指向共享内存的指针,失败返回-1。

    3.将共享内存从当前进程分离

    int shmdt(const void *shm_addr);
    shm_addr是shmat返回的地址指针,成功返回0,失败返回-1,将共享内存分离并未删除它,只是将进程与共享内存之间的连接断开。

    4.共享内存的控制函数

    int shmctl(int shm_id, int command, struct shmid_ds *buf);
    shm_id共享内存标识符,command是要采取的动作,有三种分别为将shm_ds中的数据设置为共享内存的关联值、若有权限则将共享内存关联值设置为shmid_ds结构中的值、删除共享内存,buf是指向包含共享内存模式和权限的结构。

    编程实例

    //shmA.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    #include<sys/shm.h>
    #include"sem.h"
    
    itn main()
    {
    	int shmid = shmget((key_t)1234, 128, IPC_CREAT |0664);
    	assert(shmod != -1);
    
    	int semVal = 1;
    	int semid = SemGet(1000, &semVal, 1);
    
    	char *ptr = (char*)shmat(shmid, NULL, 0);
    	assert(ptr != (char*)-1);
    
    	while(1)
    	{
    		index = 0;
    		SemP(semid, &index, 1);
    		printf("please input: ");
    		fgets(ptr, 128, stdin);
    
    		SemV(semid, &index, 1);
    
    		if(strncmp(ptr, "end", 3) == 0)
    		{
    			break;
    		}
    	}
    	shmdt(ptr);
    }
    
    //shmB.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<unistd.h>
    #include<string.h>
    #include<assert.h>
    #include<sys/shm.h>
    #include"sem.h"
    
    itn main()
    {
    	int shmid = shmget((key_t)1234, 128, IPC_CREAT |0664);
    	assert(shmod != -1);
    
    	int semVal = 1;
    	int semid = SemGet(1000, &semVal, 1);
    
    	char *ptr = (char*)shmat(shmid, NULL, 0);
    	assert(ptr != (char*)-1);
    
    	while(1)
    	{
    		nt index = 0;
    		SemP(semid, &index, 1);
    
    		if(strncmp(ptr, "end", 3) == 0)
    		{
    			break;
    		}
    
    		printf("lenth = %d :  %s", strlen(ptr) - 1, ptr);
    		sleep(2);
    		SemV(semid, &index, 1);
    	}
    	shmdt(ptr);
    }
    

    套接字
      见博客网络上不同主机进程间通讯
    相关Linux系统命令
    Ipcs –m 查看共享内存
    Ipcrm –m shmid 删除共享内存
    Ipcs –s 查看信号量
    Ipcrm –s semid 删除信号量
    Ipcs –q 查看消息队列
    Ipcrm –q msgid 删除消息队列

    进程间通讯总结:
    信号 & 信号量 不发送真实数据
    管道,消息队列,共享内存 发送真实数据

    通讯方式 内容 效率 实质 进程数量 阻塞机制
    有名管道 数据 磁盘上标识 2个 read
    无名管道 数据 父子进程共享文件描述符 父子两个进程 read
    消息队列 消息 内核对象 n msgrcv
    信号量 同步 - 内核对象 n P操作
    共享内存 数据 内核对象 2个 P操作
    展开全文
  • 在操作系统中,每一个进程都是独立的执行体,但是进程之间需要相互交互,所以就有了进程间通讯。 Linux下进程间的通讯方式有:信号、信号量、管道、消息队列、共享内存、套接字等。 1、信号 信号是系统预先定义...

         在操作系统中,每一个进程都是独立的执行体,但是进程之间需要相互交互,所以就有了进程间通讯。

         Linux下进程间的通讯方式有:信号、信号量、管道、消息队列、共享内存、套接字等。

    1、信号

    信号是系统预先定义好的一些特定的事件,信号可以被产生,也可以被接收,产生和接收的主体都是进程。接收到信号的进程会采取相应的一些行动。一般信号是由于某些错误条件而生成的,比如内存段冲突、浮点处理器错误或非法指令等。信号也可以作为进程间传递消息或修改行为的一种方式,明确的由一个进程发送给另一个进程。接收到信号的进程有三种响应方式分别为:忽略(SIG_IGN) 默认(SIG_DFL) 自定义(自定义的函数)

    进程修改信号响应方式的函数:

    进程发送信号的函数:向指定进程发送制定的信号

    改变信号的响应方式:

     

    信号的内核实现:

    2、信号量 

    信号量可以完成进程间的同步控制,进程同步就是一个进程的执行必须等待另一个进程使某种条件的发生。信号量相当于一个特殊的计数器,在其值大于0时,记录资源能被几个进程使用,当其值小于0时,记录等待资源的进程数。

    临界资源:同一时刻,只允许一个进程访问的资源。

    原子操作:该操作不会在执行完毕前被任何其他任务或事件打断,也不可分割。

    p操作   原子减一   获取资源,当信号量为0时,p操作阻塞

    v操作   原子加一   释放资源

    信号量的操作:

    (1)创建或获取:

    (2)p、v操作: 

    (3)操作控制:

    展开全文
  • 同一进程下的线程可以共享什么?

    千次阅读 2019-09-10 22:12:02
    线程独占的资源: ...1.进程代码 2.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯) 3.进程打开的文件描述符 4.信号的处理器 5.进程的当前目录 6.进程用户ID与进程组ID ...

    线程独占的资源:

    1.线程ID
    2.寄存器组的值
    3.线程的堆栈
    4.错误返回码
    5.线程的信号屏蔽码

    线程间共享的资源:

    1.进程代码段
    2.进程的公有数据(利用这些共享的数据,线程很容易的实现相互之间的通讯)
    3.进程打开的文件描述符
    4.信号的处理器
    5.进程的当前目录
    6.进程用户ID与进程组ID

    展开全文
  • 线程与进程之间的关系和区别

    千次阅读 2016-07-20 15:56:01
    线程共享的环境包括:进程代码进程的公有数据(利用这些数据,线程很容易实现相互通讯),进程打开的文件描述符,信号的处理器进程的当前目录和进程用户ID与进程组ID。 进程拥有这许多共性的同时,还拥有...

    线程共享的环境包括:进程代码段,进程的公有数据(利用这些数据,线程很容易实现相互间的通讯),进程打开的文件描述符,信号的处理器进程的当前目录和进程用户ID与进程组ID。


    进程拥有这许多共性的同时,还拥有自己的个性。有了这些个性,线程才能实现并发性。这些个性包括:
    1.线程ID。2.寄存器组的值。3.线程的堆栈(堆栈是保证线程独立运行所必需的)。4.错误码的返回值。5.线程的信号屏蔽码(但所有的线程都共享同样的信号处理器)。6.线程的优先级

    在一个进程的线程共享堆区,而进程中的线程各自维持自己堆栈。
    在 windows 等平台上,不同线程缺省使用同一个堆,所以用 C 的 malloc (或者 windows 的 GlobalAlloc)分配内存的时候是使用了同步保护的。如果没有同步保护,在两个线程同时执行内存操作的时候会产生竞争条件,可能导致堆内内存管理 混乱。比如两个线程分配了统一块内存地址,空闲链表指针错误等。 

      Symbian 的线程一般使用独立的堆空间。这样每个线程可以直接在自己的堆里分配和释放,可以减少同步所引入的开销。当线程退出的时候,系统直接回收线程的堆空间,线程内没有释放的内存空间也不会造成进程内的内存泄漏。 

      但是两个线程使用共用堆的时候,就必须用 critical section 或者 mutex 进行同步保护。否则程序崩溃时早晚的事。如果你的线程需要在共用堆上无规则的分配和释放任何数量和类型的对象,可以定制一个自己的 allcator,在 allocator 内部使用同步保护。线程直接使用这个 allocator 分配内存就可以了。这相当于实现自己的 malloc,free。但是更建议你重新审查一下自己的系统,因为这种情况大多数是不必要的。经过良好的设计,线程的本地堆应该能够满足大多数对象的需 求。如果有某一类对象需要在共享堆上创建和共享,这种需求是比较合理的,可以在这个类的 new 和 delete 上实现共享保护。 

    进程是资源分配的基本单位,线程是系统调度的基本单位。
    平时我们写的程序都是作为线程运行的;进程可以看做是包括一系列线程和资源的统称;一个进程至少包括一个
    线程(主线程,进入main函数时产生的);在其中可以创建其它线程,也可以不创建。
    同一进程间的线程究竟共享哪些资源呢,而又各自独享哪些资源呢?
    共享的资源有
    a. 堆  由于堆是在进程空间中开辟出来的,所以它是理所当然地被共享的;因此new出来的都是共享的(16位平台上分全局堆和局部堆,局部堆是独享的)
    b. 全局变量 它是与具体某一函数无关的,所以也与特定线程无关;因此也是共享的
    c. 静态变量 虽然对于局部变量来说,它在代码中是“放”在某一函数中的,但是其存放位置和全局变量一样,存于堆中开辟的.bss和.data段,是共享的
    d. 文件等公用资源  这个是共享的,使用这些公共资源的线程必须同步。Win32 提供了几种同步资源的方式,包括信号、临界区、事件和互斥体。
    独享的资源有
    a. 栈 栈是独享的
    b. 寄存器  这个可能会误解,因为电脑的寄存器是物理的,每个线程去取值难道不一样吗?其实线程里存放的是副本,包括程序计数器PC

    进程的三种状态及转换

        进程在运行中不断地改变其运行状态。通常,一个运行进程必须具有以下三种基本状态。

     就绪(Ready)状态

        当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

     执行(Running)状态
    当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

     阻塞(Blocked)状态
    正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。
    引起进程阻塞的事件可有多种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等

                                                      
    1:就绪->执行, 当前运行进程阻塞,调度程序选一个优先权最高的进程占有处理机;
    2:执行->就绪, 当前运行进程时间片用完;
    3:执行->阻塞,当前运行进程等待键盘输入,进入了睡眠状态。
    4:阻塞->就绪,I/O操作完成,被中断处理程序唤醒。


    进程的执行状态分为:核心态和用户态,两者的主要区别就是在于进程能否获取计算机的所有资源(核心态可以,用户态则受到限制)。凡是涉及到计算机根本运行的事情都应该在内核态下执行,而中断、时钟日期、存储映象图都属于系统级的资源,对这些资源的修改则都必须在核心态,但是读取则没有强制要求。

    进程的组成:进程有PCB(进程控制块)、有关程序段、和该程序段对其进行操作的数据结构集组成。

    创建进程的必须步骤:
    1.申请空白PCB(进程控制块)
    2.为新进程分派资源
    3.初始化PCB
    4.将新进程插入就绪队列


    进程于线程的主要区别:
    进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一 个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程 序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。

    线程和进程的区别联系:
    1,进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品。
    2,线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
    两者都可以提高程序的并发度,提高程序运行效率和响应时间。
    线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
    根本区别就一点:用多进程每个进程有自己的地址空间(address space),线程则共享地址空间。所有其它区别都是由此而来的:
    1、速度:线程产生的速度快,线程间的通讯快、切换快等,因为他们在同一个地址空间内。
    2、资源利用率:线程的资源利用率比较好也是因为他们在同一个地址空间内。
    3、同步问题:线程使用公共变量/内存时需要使用同步机制还是因为他们在同一个地址空间内
    展开全文
  • 0200 代码应小于 64K。  0201 操作系统无法运行 %1。  0202 操作系统无法运行 %1。  0203 系统找不到输入的环境选项。  0205 在命令子树中的进程没有信号句柄。  0206 文件名或扩展名太长。  ...
  • 因此多线可以充分利用多核,而且因为共享资源,线程间数据共享便于程序开发,而进程间通讯就没有那么方便。 但是由于多个线程共享同一进程的资源,如果其中一个线程现了段错误或者其它的致命错误,会导致整个程序...
  • Linux C 一站式学习

    2011-09-20 10:02:29
    4. 进程间通信 4.1. 管道 4.2. 其它IPC机制 5. 练习:实现简单的Shell 31. Shell脚本 1. Shell的历史 2. Shell如何执行命令 2.1. 执行交互式命令 2.2. 执行脚本 3. Shell的基本语法 3.1. 变量 3.2. 文件名代换...
  • 进程互斥体现了进程之间对资源的竞争关系,这时进程相互之间不一定清楚其它进程情况,往往指多个任务多个进程间通讯制约,因而使用更广泛。如打篮球时双方挣抢篮板球等。 (2)临界区 并发进程中与...
  • Linux C 编程一站式学习.pdf

    千次下载 热门讨论 2010-11-24 01:27:27
    4. 段错误 11. 排序与查找 1. 算法的概念 2. 插入排序 3. 算法的时间复杂度分析 4. 归并排序 5. 线性查找 6. 折半查找 12. 栈与队列 1. 数据结构的概念 2. 堆栈 3. 深度优先搜索 4. 队列与广度优先搜索 5. 环形队列 ...
  • 4. 段错误 11. 排序与查找 1. 算法的概念 2. 插入排序 3. 算法的时间复杂度分析 4. 归并排序 5. 线性查找 6. 折半查找 12. 栈与队列 1. 数据结构的概念 2. 堆栈 3. 深度优先搜索 4. 队列与广度优先搜索 5. 环形队列 ...
  • 只是把模块之间的进程内调用改为进程间调用,这种切分不可取,违反了分布式第一原则,模块耦合没有解决,性能却受到了影响。 分布式设计第一原则 -- “不要分布你的对象” <ul><li>...
  • v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 51 .c .h .o v27.xx 鸿蒙内核源码分析(互斥锁篇) | 比自旋锁丰满的互斥锁 | 51 .c .h .o v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当立贞节...
  • VA是一个标准的沙盒,或者说“虚拟机”,提供了一整套内部与外部的隔离机制,包括但不限于(文件隔离/组件隔离/进程通讯隔离),简单的说VA内部就是一个“完全独立的空间”。在此基础之上,稍作定制即可实现一部手机上...
  • 1.1.8 NFS 和 SMB 是最常见的两种 NAS(Network Attached Storage)协议,当把一个文件系统同时通过 NFS 和 SMB 协议共享给多个主机访问时,以下哪些说法是错误的 1.1.9 输入 ping IP 后敲回车,发包前会发生什么?...
  • windowsnt 技术内幕

    2014-04-09 20:47:17
    4.0 Windows NT网络协议简介 MUP简介 Multiple Provider Router简介 理解传输驱动动器接口(TDI) 理解文件系统驱动器 理解分布式处理 理解进行进程间通信机制 访问文件和打印资源 分布式文件和打印资源 分布式文件...
  • vc++ 开发实例源码包

    2014-12-16 11:25:17
    内含各种例子(vc下各种控件的使用方法、标题栏与菜单栏、工具栏与状态栏、图标与光标、程序窗口、程序控制、进程与线程、字符串、文件读写操作、文件与文件夹属性操作、文件与文件夹系统操作、系统控制操作、程序...
  • 它通过 socket 跟 Server 进行通讯,等待测试任务的分配。 <p><img alt="labor" src="https://img-blog.csdnimg.cn/img_convert/8e9b781b2303942d6cb2501fc1e43dfe.png" /></p> 某个时刻,Server 给该 ...
  •  栈是一种线形集合,其添加和删除元素的操作应在同一完成。栈按照后进先出的方式进行处理。 堆是栈的一个组成元素 22、forward 和redirect的区别  forward是服务器请求资源,服务器直接访问目标地址的URL,把...
  • 在一个文本文件的段间插入空行 9-11. 利用修改文件名,来转换图片格式 9-12. 模仿getopt 命令 9-13. 提取字符串的一种可选的方法 9-14. 使用参数替换和error messages 9-15. 参数替换和"usage"messages 9-16. 变量...
  • Linux高级bash编程

    2009-07-28 10:26:07
    在一个文本文件的段间插入空行 9-11. 利用修改文件名,来转换图片格式 9-12. 模仿getopt命令 9-13. 提取字符串的一种可选的方法 9-14. 使用参数替换和error messages 9-15. 参数替换和"usage"messages 9-16. 变量...
  • 深入学习shell脚本艺术

    热门讨论 2011-02-22 04:01:01
    在一个文本文件的段间插入空行 9-11. 利用修改文件名,来转换图片格式 9-12. 模仿getopt命令 9-13. 提取字符串的一种可选的方法 9-14. 使用参数替换和error messages 9-15. 参数替换和"usage"messages 9-16. 变量...
  • java 面试题 总结

    2009-09-16 08:45:34
    栈是一种线形集合,其添加和删除元素的操作应在同一完成。栈按照后进先出的方式进行处理。 堆是栈的一个组成元素 19、forward 和redirect的区别 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL...
  • <ul><li>服务之间的通讯机制RPC开销大</li><li>需要考虑分布式情况下的服务失效恢复等等问题</li><li>数据库分布带来的分布式事务困扰,还有分布式数据结果Join的问题</li><li>如何管理这么多服务之间的依赖...
  • 3、微服务强调每个微服务都有自己独立的运行空间,包括数据库资源,JVM的运行资源等,每个服务运行在其独立的进程中,服务与服务采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。 4、微服务架构...
  • asp.net知识库

    2015-06-18 08:45:45
    ASP.Net应用程序的多进程模型 NET委托:一个C#睡前故事 [推荐] - [原创] Microsoft .NET策略及框架概述 卸载Class? Web Form 窗体 如何实现web页面的提示保存功能 在ASP.Net中两种利用CSS实现多界面的方法 如何在...
  •  函数的值是指函数被调用之后, 执行函数体中的程序所取得的并返回给主调函数的值。如调用正弦函数取得正弦值,调用例5.1的max函数取得的最大数等。对函数的值(或称函数返回值)有以下一些说明: 1. 函数的值只能...

空空如也

空空如也

1 2
收藏数 28
精华内容 11
关键字:

进程间通讯段错误