1动态链接库和静态链接库的优缺点
1 静态链接库的优点
(1) 代码装载速度快,执行速度略比动态链接库快;
(2) 只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。
2 动态链接库的优点
(1) 更加节省内存并减少页面交换;
(2) DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;
(3) 不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
(4)适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。
3 不足之处
(1) 使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;
(2) 使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。
2轮询任务调度和可抢占式调度有什么区别?
(1)轮询调度的原理是每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。只有在当前任务主动放弃CPU控制权的情况下(比如任务挂起),才允许其他任务(包括高优先级的任务)控制CPU。其优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。但不利于后面的请求及时得到响应。
(2)抢占式调度允许高优先级的任务打断当前执行的任务,抢占CPU的控制权。这有利于后面的高优先级的任务也能及时得到响应。但实现相对较复杂且可能出现低优先级的任务长期得不到调度。
3列出数据库中常用的锁及其应用场景
数据库中的锁是网络数据库中的一个非常重要的概念,它主要用于多用户环境下保证数据库完整性和一致性。各种大型数据库所采用的锁的基本理论是一致的,但在具体实现上各有差别。目前,大多数数据库管理系统都或多或少具有自我调节、自我管理的功能,因此很多用户实际上不 清楚锁的理论和所用数据库中锁的具体实现。在数据库中加锁时,除了可以对不同的资源加锁,还可以使用不同程度的加锁方式,即锁有多种模式,SQL Server中锁模式包括:
1)共享锁
SQL Server中,共享锁用于所有的只读数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源。默认情况下,数据被读取后,SQL Server立即释放共享锁。例如,执行查询“SELECT * FROM my_table”时,首先锁定第一页,读取之后,释放对第一页的锁定,然后锁定第二页。这样,就允许在读操作过程中,修改未被锁定的第一页。但是,事务 隔离级别连接选项设置和SELECT语句中的锁定设置都可以改变SQL Server的这种默认设置。例如,“ SELECT * FROM my_table HOLDLOCK”就要求在整个查询过程中,保持对表的锁定,直到查询完成才释放锁定。
2)修改锁
修 改锁在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁造成的死锁现象。因为使用共享锁时,修改数据的操作分为两步,首先获得一 个共享锁,读取数据,然后将共享锁升级为独占锁,然后再执行修改操作。这样如果同时有两个或多个事务同时对一个事务申请了共享锁,在修改数据的时候,这些 事务都要将共享锁升级为独占锁。这时,这些事务都不会释放共享锁而是一直等待对方释放,这样就造成了死锁。如果一个数据在修改前直接申请修改锁,在数据修 改的时候再升级为独占锁,就可以避免死锁。修改锁与共享锁是兼容的,也就是说一个资源用共享锁锁定后,允许再用修改锁锁定。
3)独占锁
独占锁是为修改数据而保留的。它所锁定的资源,其他事务不能读取也不能修改。独占锁不能和其他锁兼容。
4)结构锁
结构锁分为结构修改锁(Sch-M)和结构稳定锁(Sch-S)。执行表定义语言操作时,SQL Server采用Sch-M锁,编译查询时,SQL Server采用Sch-S锁。
5)意向锁
意 向锁说明SQL Server有在资源的低层获得共享锁或独占锁的意向。例如,表级的共享意向锁说明事务意图将独占锁释放到表中的页或者行。意向锁又可以分为共享意向锁、 独占意向锁和共享式独占意向锁。共享意向锁说明事务意图在共享意向锁所锁定的低层资源上放置共享锁来读取数据。独占意向锁说明事务意图在共享意向锁所锁定 的低层资源上放置独占锁来修改数据。共享式独占锁说明事务允许其他事务使用共享锁来读取顶层资源,并意图在该资源低层上放置独占锁。
6)批量修改锁
批量复制数据时使用批量修改锁。可以通过表的TabLock提示或者使用系统存储过程sp_tableoption的“table lock on bulk load”选项设定批量修改锁。
4给定N是一个正整数,求比N大的最小“不重复数”,这里的不重复是指没有两个相等的相邻位,如1102中的11是相等的两个相邻位故不是不重复数,而12301是不重复数。
#include <iostream>
#include <cstdio>
using namespace std;
void fun(int);
int main()
{
int n;
while (scanf("%d", &n))
{
fun(n + 1);
}
return 0;
}
void fun(int n)
{
while (1)
{
bool flag = false;
int a[20] = {0};
int b = 0;
int len = 0;
while (n)
{
a[len++] = n % 10;
n /= 10;
}
for (int i = len - 1; i > 0; i--)
{
if (a[i] == a[i - 1] && !flag)
{
a[i - 1]++;
flag = true;
}
else if(flag)
{
a[i - 1] = b;
b = (b == 0) ? 1 : 0;
}
}
for (int i = len - 1; i >= 0; i--)
{
n = n * 10 + a[i];
}
if (!flag)
{
printf("%d\n", n);
break;
}
}
}
5设N是一个大整数,求长度为N的字符串的最长回文子串。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
void fun(char*, int);
int main()
{
char ch[100];
while (1)
{
gets(ch);
if (strlen(ch) == 0) break;
fun(ch, strlen(ch));
}
fun(ch, strlen(ch));
return 0;
}
void fun(char *ch, int len)
{
int res_len = 1;
int res_left = 0;
int res_right = 0;
int left, right;
for (int i = 1; i < len - 1; i++)
{
//长度为奇数的情况
left = i - 1;
right = i + 1;
while (left >= 0 && right <= len - 1 && ch[left] == ch[right])
{
--left;
++right;
}
if (right - left + 1 > res_len)
{
res_left = left + 1;
res_right = right - 1;
res_len = res_right - res_left + 1;
}
//长度为偶数的情况
left = i - 1;
right = i;
while (left >= 0 && right <= len - 1 && ch[left] == ch[right])
{
--left;
++right;
}
if (right - left + 1 > res_len)
{
res_left = left + 1;
res_right = right - 1;
res_len = res_right - res_left + 1;
}
}
for (int j = res_left; j <= res_right; j++)
{
printf("%c", ch[j]);
}
printf(", maxlen is %d\n", res_len);
}
6数轴上从左到右有 n 个点 a[0],a[1],„„,a[n-1],给定一根长度为 L 的绳子,求绳子最多能 覆盖其中的几个点。
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int maxCover(int *a, int n, int L)
{
int count = 2; int maxCount = 1;
int i = 0;
int j = 1;
int start;
while (i < n && j < n)
{
while (j < n && a[j] - a[i] <= L)
{
j++;
count++;
}
j--;
count--;
if (count > maxCount)
{
maxCount = count;
start = i;
}
i++;
j++;
}
for (int k = start; k < start + maxCount; k++)
{
printf("%d ", a[k]);
}
printf("\n");
return maxCount;
}
int main()
{
int a[] = {1, 3, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 21};
printf("max count: %d\n\n", maxCover(a, 13, 8));
int b[] = {1,2,3,4,5,100,1000};
printf("max count: %d\n", maxCover(b, 7, 8));
return 0;
return 0;
}
进程与线程的区别和联系
一、程序与进程
程序: 一段静态的代码
进程: 程序的一次动态执行过程
二、 进程与线程
进程: 进程是进程实体(程序段 数据段 PCB)的运行过程,是系统进行资源分配和调度的一个独立单位;
线程: 又称轻量级进程(lightweight process),是进程中某个单一顺序的控制流;
三、 进程与线程的区别
1. 地址空间和资源:进程间相互独立,同一进程的线程间共享;
2. 通信:线程间可以直接通信(共享区),进程需要别的手段(信号、信号量、共享存储、管道通信、消息队列)
3. 调度:线程切换更快;线程是独立调度的基本单位,进程是独立资源分配的基本单位;