标签:进程通信 联系 connect ndt 设置 critical 信号量 accept 流程
文件IO
回调函数是由别人的函数执行时调用的函数.
不带缓冲的文件IO 每个read和write都调用内核中的一个系统调用
只要涉及在多进程间通信共享资源.原子操作就变成非常重要.
函数:
int open(const char pathname, int oflag,..mode);
int create(const char *pathname,mode_t mode);
off_t lseek(int filedes,off_t offset,int where) //SEEK_SET SEEK_CUR SEEK_END
close(fd);
int dup(int filedes);//返回文件描述符中的最小值 共享一个文件表项
int dup2(int filedes,int filedes2);//
复制描述符: fcntl(filedes,F_DUPFD,0);
int create(const char pathname,mode)
size_t write(int fileds, const void buff,size_t nbytes);
int stat(const char pathname, struct stat buf);//返回文件信息结构
int fstat(int filedes,strcut stat buf);
od -c file 观察该文夹的实际内容
size_t read(int filedes,void buf,size_t nbytes);
原子操作: 指不会被线程调度机制打断的操作.
信号量:
信号量用在多线程多任务同步的,一个线程完成了某一个动作就通过信号量告诉别的线程在进行某些动作.别的线程再进行某些动作.
常用函数:
memset(&servaddr,0,sizeof(servaddr));
recvfrom(fd,buf,6,0,NULL,NULL);
sendto(fd,"hello",6,0,(struct sockaddr *)&servaddr,sizeof(servaddr));
ret = connect(fd,(struct sockaddr *)&servaddr,sizeof(servaddr)); 成功为零
qt:: socket->read(str,20);//读去字节
QString text=QString::fromLocal8Bit(str);//把字符串转化为QString
stuDao *sd = new stuDaolmp();//使用了多态 业务逻辑
DBHelper* DBHelper::instance = 0;
cs->moveToThread(thread);//把对象移入线程
MYSQL:
以行列二维表形式表示和存储数据的数据库
约束:
unique null default foreign key auto_inrement primary key
select id,name,class form Tab grounp by class order by scoer limit 3;
第一范式: 每个属性不可在分:
第二范式:
第三范式:除了主键,其他字段不存在依赖关系
100条c笔试题:
1 float x 与零值比较: const float EPSINON = 0.00001; if((x>=-EPSINON)&&(x<=EPSINON))
2 没有为str分配空间,进行拷贝将发生异常,可以正常读写,但因为越界而导致程序崩溃.
3 程序崩溃,mallo不能返回动态空间给str
中间件是一种独立的系统软件或服务程序,分布式应用软件借助这种软件在不同的技术之间共享资源.
中间件是一类链接软件组件和应用的计算机软件.
中间件在操作系统,网络和数据库之上,应用软件的下层.
一些特点:
1 满足大量应用的需求
2 运行于多种硬件和os平台
3 支持分布式计算,提供跨网络,硬件,和os 平台的透明性的应用和交互
4 支持标准的协议
5 支持标准的io
应用服务器:
是通过各种协议把商业逻辑保罗给客户端的程序.它提供了访问商业逻辑的途径以供客户端应用程序使用,应用服务器使用此商业逻辑就像调用对象的一个方法一样.
中间件的分类: 终端仿真/屏幕转换中间件,数据访问中间件,远程过程调用中间件,消息中间件,交易中间件,对象中间件.
const 与 #define:
(1) const 常量有数据类型 #define 没有数据类型
(2) 编译器对const进行类安全检查 |#define只是字符替换
(3) 有些调试工具可以对const常量进行调试
molloc /free 和 new /delete
(1) malloc/free 是C/C++语言标准库的函数,new/delete是运算符
(2) 非内部数据类型的对象,用malloc/free无法满足动态对象的要求.对象创建需要自动执行自动自行构造函数,对象消亡需要自动执行析够函数. malloc/free不在编译器控制权限制内. 不能够把构造函数的构造和析够函数的任务强加给malloc/free
空间申请失败:
(1) return 终止函数
(2) 调用exit(1)终止程序
(3) 设置异常处理函数
判断操作系统的位数: 定义一个指针P sizeof(p) if 2 -->16 else if 4 -->32
初始化区放在data区: global int x=10;
未初始化的数据,没有必要在目标文件保存零值,这些信息保存在bass段
static int val 位与已初始化数据段
return 不能返回指向栈内存的指针或引用, 要明确返回的的值,指针还是引用, 如果返回的是一个对象,要考虑return语句的效率.]
return string(s1+s2) 创建一个临时对象并把它返回,
string(temp s1+s2) return temp;
将发生三件事, 1 temp对象创建 2 拷贝构造函数把temp拷贝到外部存储单元 3 temp 被析够
输出运算符优先级高于条件操作符
十六进制转整形
int main(void)
{
int i,mid;
int len = srelen(shex);
if(len>8)
return FALSE;
mid = 0;
idec =0;
for(i =0;i<len;i++)
{
if(shex[i] >‘0‘&& shex[i]<=‘9‘)
mid = shex[i]-‘0‘;
else if(shex[i]>=‘a‘&&a[i]<=‘f)
mid = shex[i]-‘0‘+10;
else if(shex[i]>=‘A‘&shex[io]<=‘F‘)
mid = shex[i]-‘0‘+10;
else return 0;
mid <<=(len-i-)<<2);//移位表示变为2的n次方
idec = idec+mid;
}
reutrn 1;
}
void frequency(string &s,char& A[],int &C[],int &k)
{
int i,j,len = length();
if(!len) {cout<<"The string is empty"<<endl;k=0;return;}
else
{
A[0] = s[0];
for(i =1;i<len;i++)
C[i]=0;
for(i=1;i<len;i++)
j =0;
while(j<k&&)
}
}
//字符串替换
int find(String &str, string & t)
{
if(str.size()<t.size())
{ cout<<"error";
return -1;
}
const int n = str.size();
char* p = new char[n];
memset(p,0,n);
for(i=0;i<str.size()-t.size()<<i++)
{
if(str[i]==min[0])
{
strncpy(p,str.c_str()+i,t.size());
if(strcmp(p,t.c_str())==0)
return i;
}
}
return 0;
}
string &string:;Repalce(string& t,string & v)
{
if((int id = find(t))==-1)
{cout<<"the (replace) failed"<<endl;}
string temp(ch);
ch[0] ="\0";
curlen = 0;
int j,k=0,l;
while(id != -1)
{
for(j=0;j<id;j++)
{
ch[k++] =temp.ch[j];
}
}
}
1 结构体和联合体的区别?
联合体的各个成员共用内存,并应该同时只能有一个成员得到这块内存的使用权.
结构体各个成员各自拥有内存,各自使用互不干涉。
所以,某种意义上来说,联合体比结构体节约内存。
2 判断浮点数是否相等?
一般float型只能精确到小数后六位(即1e-6),将float型数据的绝对值与1e-6比较,来判断是否相等(为零)。
3 top ?
top 命令实时显示进程的状态。
4 存储方式?
一个变量的创建是要在内存中开辟空间的。
数据存储有两种模式:大端格式和小端格式
5 ip协议?
①IP协议是一种无连接、不可靠的分组传送服务的协议。
②IP协议是点-点线路的网络层通信协议。:IP协议是针对原主机-路由器、路由器-路由器、路由器-目的主机之间的数据传输的点-点线路的网络层通信协议。
③IP协议屏蔽了网络在数据链路层、物理层协议与实现技术上的差异。:通过IP协议,网络层向传输层提供的是统一的IP分组,传输层不需要考虑互联网在数据链路层、物理层协议与实现技术上的差异,IP协议使得异构网络的互联变得容易了。
互联网协议(Internet Protocol Suite)是一个网络通信模型, ip网络层,tcp,udp 传输层
6 mac?
MAC地址(Media Access Control Address),直译为媒体访问控制地址,也称为局域网地址(LAN Address),以太网地址(Ethernet Address)或物理地址(Physical Address),它是一个用来确认网上设备位置的地址。第三层网络层负责IP地址,第二层数据链接层则负责MAC地址。MAC地址用于在网络中唯一标示一个网卡,一台设备若有一或多个网卡,则每个网卡都需要并会有一个唯一的MAC地址。
7 进程间通信方式?
1. 管道pipe:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
2. 命名管道FIFO:有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
4. 消息队列MessageQueue:消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
5. 共享存储SharedMemory:共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
6. 信号量Semaphore:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
7. 套接字Socket:套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机间的进程通信。
8. 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
8 线程的同步和异步?
并发:同一时间段有几个程序都处于已经启动到运行完毕之间,并且这几个程序都在同一个处理机上运行,并发的两种关系是同步和互斥;
互斥:进程之间访问临界资源时相互排斥的现象;
同步:进程之间存在依赖关系,一个进程结束的输出作为另一个进程的输入。具有同步关系的一组并发进程之间发送的信息称为消息或者事件;
并行:单处理器中进程被交替执行,表现出一种并发的外部特征;在多处理器中,进程可以交替执行,还能重叠执行,实现并行处理,并行就是同事发生的多个并发事件,具有并发的含义,但并发不一定是并行,也就是说事件之间不一定要同一时刻发生;
多线程:多线程是进程中并发运行的一段代码,能够实现线程之间的切换执行;
异步:和同步相对,同步是顺序执行,而异步是彼此独立,在等待某个事件的过程中继续做自己的事,不要等待这一事件完成后再工作。线程是实现异步的一个方式, 异步是让调用方法的主线程不需要同步等待另一个线程的完成,从而让主线程干其他事情。
异步和多线程:不是同等关系,异步是目的,多线程只是实现异步的一个手段,实现异步可以采用多线程技术或者交给其他进程来处理。
同步:也就是必须一件一件事做,等前一件做完了才能做下一件事。可以理解为同步是指两个线程的运行是相关的,其中一个线程要阻塞等待另外一个线程的运行。异步的意思是两个线程毫无相关,自己运行自己的。
同步机制:
(1)事件(Event);
(2)信号量(semaphore);
(3)互斥量(mutex);
(4)临界区(Critical section)。
死锁: 死锁是指多个线程因竞争资源而造成的一种互相等待的僵局。
String(const char* str = "")
{
if (NULL == str)
{
_str = new char[1];
_str = ‘\0‘;
}
else
{
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
}
class String
{
public:
String(const char *str = NULL); //通用构造函数
String(const String &str); //拷贝构造函数
~String(); //析构函数
String operator+(const String &str) const; //重载+
String& operator=(const String &str); //重载=
String& operator+=(const String &str); //重载+=
bool operator==(const String &str) const; //重载==
char& operator[](int n) const; //重载[]
size_t size() const; //获取长度
const char* c_str() const; //获取C字符串
friend istream& operator>>(istream &is, String &str);//输入
friend ostream& operator<<(ostream &os, String &str);//输出
private:
char *data; //字符串
size_t length; //长度
};
String::String(const char *str)//通用构造函数
{
if (!str)
{
length = 0;
data = new char[1];
*data = ‘\0‘;
}
else
{
length = strlen(str);
data = new char[length + 1];
strcpy(data, str);
}
}
String::String(const String &str)//拷贝构造函数
{
length = str.size();
data = new char[length + 1];
strcpy(data, str.c_str());
}
String::~String()//析构函数
{
delete []data;
length = 0;
}
String String::operator+(const String &str) const//重载+
{
String newString;
newString.length = length + str.size();
newString.data = new char[newString.length + 1];
strcpy(newString.data, data);
strcat(newString.data, str.data);
return newString;
}
String& String::operator=(const String &str)//重载=
{
if (this == &str) return *this;
delete []data;
length = str.length;
data = new char[length + 1];
strcpy(data, str.c_str());
return *this;
}
String& String::operator+=(const String &str)//重载+=
{
length += str.length;
char *newData = new char[length + 1];
strcpy(newData, data);
strcat(newData, str.data);
delete []data;
data = newData;
return *this;
}
inline bool String::operator==(const String &str) const//重载==
{
if (length != str.length) return false;
return strcmp(data, str.data) ? false : true;
}
inline char& String::operator[](int n) const//重载[]
{
if (n >= length) return data[length-1]; //错误处理
else return data[n];
}
inline size_t String::size() const//获取长度
{
return length;
}
istream& operator>>(istream &is, String &str)//输入
{
char tem[1000]; //简单的申请一块内存
is >> tem;
str.length = strlen(tem);
str.data = new char[str.length + 1];
strcpy(str.data, tem);
return is;
}
ostream& operator<<(ostream &os, String &str)//输出
{
os << str.data;
return os;
}
inline const char* String::c_str() const//获取C字符串
{
return data;
}
extern是计算机语言中的一个关键字,可置于变量或者函数前,以表示变量或者函数的定义在别的文件中。提示编译器遇到此变量或函数时,在其它模块中寻找其定义
class Empty
2:
3: {
4:
5: public:
6:
7: Empty(); // 缺省构造函数
8:
9: Empty( const Empty& ); // 拷贝构造函数
10:
11: ~Empty(); // 析构函数
12:
13: Empty& operator=( const Empty& ); // 赋值运算符
14:
15: Empty* operator&(); // 取址运算符
16:
17: const Empty* operator&() const; // 取址运算符 const
18:
19: };
map是一类关联式容器。它的特点是增加和删除节点对迭代器的影响很小,除了那个操作节点,对其他的节点都没有什么影响。
对于迭代器来说,可以修改实值,而不能修改key。map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的,后边我们会见识到有序的好处。2、map的功能
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。
抽象类主要用来进行类型隐藏。构造出一个固定的一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。
使用多态能够增强程序的可扩充性,即程序需要修改或增加功能时,只需改动或增加较少的代码。此外,使用多态也能起到精简代码的作用。
TCP(Transmission Control Protocol 传输控制协议)是一种面向连接(连接导向)的、可靠的、 基于IP的传输层协议。TCP在IP报文的协议号是6。TCP是一个超级麻烦的协议,而它又是互联网的基础,也是每个程序员必备的基本功。
链表逆值:
node *reverse(node *head)
{
node* p,*q,*r;
if(head == NULL)
{
return head;
}
p = head->next;
q=p->next;
p->next =NULL;
while(q!=NULL)
{
r = q->next;
q->next = p;
p=q;
q=r;
}
head->next = p;
return head;
}
strcpy 代码
char* strcpy(char* Dest, const char* src);
{
if(Desc == NULL|| sec == NULL)
{
return NULL;
}
const char *p =src;
while((*p++=*Dest++)!=‘\0‘);
return Desc;
}
getlen(const char* src)
{
const char *p = src;
int strlen = 0;
while(*p++ != ‘\0‘)
{
strlen++;
}
return strlen;
}
int *(*s[10])(int *a[10])?
s是一个指针数组,存放的10个返回值为int * 参数需要存放10个int * 的数组,的函数指针
TCP/IP四层模型结构:
应用层(处理特定的应用层序),
运输层(提供端对端的通信),
网络层(处理分组在网络中的活动),
链路层(网络接口卡)
进程状态: 基本状态,即运行态,就绪态,阻塞态。
在五态模型中,进程分为新建态、就绪态, 运行态,阻塞态,终止态。
大小端? 0x1234567
大端字节序:
0x1000 0x1004 0x1008 0x10012
01 23 45 67
高位字节数据存放在低地址处,低位数据存放在高地址处;
小段字节序:
高位字节数据存放在高地址处,低位数据存放在低地址处;
析够函数定为虚函数的作用? 析构函数定义为虚函数的作用是为了程序能够调用到正确的析构函数。
重载:是指同一可访问区内被声明的几个具有不同参数列(参数的类型,个数,顺序不同)的同名函数,根据参数列表确定调用哪个函数,重载不关心函数返回类型。
隐藏:是指派生类的函数屏蔽了与其同名的基类函数,注意只要同名函数,不管参数列表是否相同,基类函数都会被隐藏。
重写(覆盖):是指派生类中存在重新定义的函数。其函数名,参数列表,返回值类型,所有都必须同基类中被重写的函数一致。只有函数体不同(花括号内),派生类调用时会调用派生类的重写函数,不会调用被重写函数。重写的基类中被重写的函数必须有virtual修饰。
重载和重写的区别:
(1)范围区别:重写和被重写的函数在不同的类中,重载和被重载的函数在同一类中。
(2)参数区别:重写与被重写的函数参数列表一定相同,重载和被重载的函数参数列表一定不同。
(3)virtual的区别:重写的基类必须要有virtual修饰,重载函数和被重载函数可以被virtual修饰,也可以没有。
隐藏和重写,重载的区别:
(1)与重载范围不同:隐藏函数和被隐藏函数在不同类中。
(2)参数的区别:隐藏函数和被隐藏函数参数列表可以相同,也可以不同,但函数名一定同;当参数不同时,无论基类中的函数是否被virtual修饰,基类函数都是被隐藏,而不是被重写。
多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。
C++多态方式:
(1)静态多态(重载,模板)
是在编译的时候,就确定调用函数的类型。
(2)动态多态(覆盖,虚函数实现)
在运行的时候,才确定调用的是哪个函数,动态绑定。运行基类指针指向派生类的对象,并调用派生类的函数。
虚函数实现原理:虚函数表和虚函数指针。
纯虚函数: virtual int fun() = 0;
常规的排序算法
选择排序:
第i趟排序(i=1,2,3…n-1)开始时,当前有序区和无序区分别为R[1..i-1]和R(i..n)。该趟排序从当前无序区中-选出关键字最小的记录 R[k],将它与无序区的第1个记录R交换,使R[1..i]和R[i+1..n)分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区;
for(i=0;i<10;i++)
{
for(j=i+1;j<10;j++)
if(a[i]<a[j])//进行比较
//比较后进行交换
{
w=a[i];
a[i]=a[j];
a[j]=w;
}
}
for(i=0;i<10-1;i++)
{
for(j=i+1;j<10-i-1;j++)
if(a[j]<a[j+1])//比较大小
{
t=a[j];
a[j]=a[j+1];
a[j+1]=t;
}
}
直接插入排序
思路:先取一个有序的队列,然后将其他数字一个一个和这个有序数列排序
for(int i=1;i<n;i++)
{
temp = a[i];
for(int j=i-1;j>=0&&temp<a[j];j--)
{
a[j+1]=a[j];
}
a[j+1] = temp;
}
快排序:
void quick_sort(int arr[],int low,int hight)
{
int i,j,pivot;
if(low < high)
{
key = a[low];
i=low;
j = hight;
while(i<j)
{
while(i<j&&a[j]>=key)
j--; //从尾部找到第一个比key值小的
if(i<j)
a[i++] = a[j];
while(i<j&&a[i]<=key)
i++; //从头找出第一个比key值大的
if(i<j)
a[j--]=a[i];
}
a[i]=pivot;
quick_sort(a,low,i-1);
quick_sort(a,i+1,high);
}
}
void quick_sort(int a[],int low,int high)
{
int i,j,key;
if(low < high)
{
key = a[low];
i=low;
j = high;
while(i<j)
{
while(i<j&&a[j]>=key)
j--; //从尾部找到第一个比key值小的
if(i<j)
a[i++] = a[j]; //放到左边
printf("交换i=%d j=%d\n",i-1,j);
while(i<j&&a[i]<=key)
i++; //从头找出第一个比key值大的 放到右边
if(i<j)
a[j--]=a[i];
printf("交换i=%d j=%d\n",i,j+1);
}
a[i]=key; //key值放在中间
printf("key=%d\n",a[i]);
quick_sort(a,low,i-1);
quick_sort(a,i+1,high);
}
}
择半查找
搜索过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜索过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。如果在某一步骤数组为空,则代表找不到。这种搜索算法每一次比较都使搜索范围缩小一半 [1] 。
int find(int a[],int n,int key)
{
int low =0;
int high = n-1;
while(low<=high)
{
mid = (low+high)/2;
if(key == a[mid])
return mid;
if(a[mid]< key)
low = mid+1;
if(a[mid]>key)
high = mid-1;
}
return -1;
}
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:是进程的一个执行单元,是进程内科调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。
线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理
socket监听流程:
服务器调用socket()、bind()、listen()完成初始化后,调用accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。
为了更好的判定socket是否断开,我判断当recv()返回值小于等于0时,socket连接断开。但是还需要判断 errno是否等于 EINTR 。如果errno == EINTR 则说明recv函数是由于程序接收到信号后返回的,socket连接还是正常的,不应close掉socket连接。
跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。
心跳检测步骤:
1 客户端每隔一个时间间隔发生一个探测包给服务器
2 客户端发包时启动一个超时定时器
3 服务器端接收到检测包,应该回应一个包
4 如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器
5 如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了
多个并发进程因争夺系统资源而产生相互等待的现象。
三、产生死锁的必要条件
(1)互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求该资源,则请求者只能等待,直至占有该资源的进程用毕释放。
(2)请求和保持条件:指进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源又被其它进程占有,此时请求进程阻塞,但又对自己获得的其它资源保持不放。
(3)不剥夺条件:指进程已获得资源,在使用完之前,不能被剥夺,只能在使用完时由自己释放。
(4)环路等待条件:指在发生死锁时,必然存在一个进程—资源的环形链,即进程集合(P0,P1,P2,…,Pn)中的P0正在等待一个P1占用的资源;P1正在等待一个P2占用的资源,……,Pn正在等待已被P0占用的资源。
TCP用主机的IP地址加上主机上的端口号作为TCP连接的端点,这种端点就叫做套接字(socket)或插口。套接字用(IP地址:端口号)表示。它是网络通信过程中端点的抽象表示
指针和引用的联系与区别
★ 相同点:
1. 都是地址的概念;
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
★ 区别:
1. 指针是一个实体,而引用仅是个别名;
2. 引用使用时无需解引用(*),指针需要解引用;
3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
4. 引用没有 const,指针有 const;
5. 引用不能为空,指针可以为空;
6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
7. 指针和引用的自增(++)运算意义不一样;
8.从内存分配上看:程序为指针变量分配内存区域,而引用不需要分配内存区域。
需要在两次调用之间对变量的值进行保存
静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指 针。
由于信号量只能进行两种操作等待和发送信号,即P(sv)和V(sv),他们的行为是这样的:
P(sv):如果sv的值大于零,就给它减1;如果它的值为零,就挂起该进程的执行
V(sv):如果有其他进程因等待sv而被挂起,就让它恢复运行,如果没有进程因等待sv而挂起,就给它加1.
TCP是面向有连接的数据通信,也就说在进行实际的数据包的收发之前,会先做好通信两端主机的准备工作:TCP三次握手!
TCP通过序列号、检验和、确认应答信号、重发控制、连接管理、窗口控制、流量控制、拥塞控制实现可靠性。
在双端主机进行数据的交互完成过之后,会进行TCP连接的断开处理
两个变量或函数的名字完全相同,就会出现冲突。
1. 修饰变量
具有常属性,可以在定义数组的时候用该变量定义,每次取值从寄存器中取,在编译过后,直接将对应的值,替换到当前变量的位置。与之相对的是volatile。被这个关键字修饰的话,代表告诉了编译器,这个变量时随时可能被修改的。防止编译器优化,每次读取该值时,从内存中读取。而不是从编译器优化的寄存器中读取。C++中,被const修饰的变量,会在编译期间将对应的变量,直接替换为该变量的值。但是C语言中不会。
2. 修饰指针
int * const p ;表示指针变量本身不能被修改,只能指向这一个地址,这与引用比较类似,一个变量的引用,在生命周期内只能引用一个对象。但是这个指针所指向的内容是可以改变的。
const int *p这表示p所指向的空间内容不可修改。C语言中int *p = 1; 可以正常运行。因为发生了隐式类型转换会出现警告。但是C++中有严格的类型检测,不允许这样进行赋值。必须显式的给出强制转换。强行转换之后对对应地址内容进行修改,C中输出 *p与m值相同,C++中 *p是修改后的值,m则是定义时的值,因为C++中被const修饰的变量,会在编译时期进行替换。
3. 修饰函数
放在返回值前 const int add(int a, int b)无意义,因为返回的值本就是一个临时变量。所以const修饰也没有任何作用
放在参数列表前修饰。用来保护传进来的参数,保证尽可能的不被修改。
放在函数后面。用来修饰类的成员函数中的this所指向的,也就是保护类成员(非静态成员除外)不被修改。同时,没有const修饰的函数可以调用const修饰的成员函数,但是被const修饰的成员函数不可以调用非const修饰的成员函数。而且非const定义出来的对象可以调用const与非const函数,但是const定义出来的对象只能调用const修饰的函数,不能调用非const函数,因为他有可能对对象进行修改。
类成员函数中,后面加与不加const也可以形成重载。const修饰的对象调用的是const修饰函数,非const修饰的对象调用的是非const函数。
4. 修饰类成员变量
const成员变量必须在类的构造函数的初始化列表中初始化,因为此时类并没有进行实例化(创建对象),因此也没有分配内存。因为类中变量只是声明时候用的cosnt来修饰,const要修饰一个变量不能被改变,总不能这个变量都没有值,就让他不能被改变吧。所以要在这个变量被创建之前就给他定义一个值。类的构造函数的初始化列表中就可以在对象创建之前做到这一点。如果不在构造函数初始化列中给出值,有可能在构造函数体中,这个const成员已经指向了一个随机的初始值。这样就不切合实际了。
如果是static const 同时修饰的类成员变量。可以在类的内部声明时给出初始化。同时在类外(全局作用域)进行声明。否则不会为这个变量分配空间。
标签:进程通信 联系 connect ndt 设置 critical 信号量 accept 流程
原文地址:https://www.cnblogs.com/countryboy666/p/10958342.html