Linux笔试面试题总结

Linux

一、Linux进程间通信方式有那些?
1.管道(pipe)和有名管道(name pipe 如FIFO)
管道只能用于有亲缘关系的进程间通信,如父子进程间通信
而,有名管道可以用于任何进程间通信

2.信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身;

3.消息队列(message)
消息队列是消息的链接表,存储在内核中,由消息队列标识符标识。

4.共享内存

5.信号量
信号量是一个计数器,用于为多个进程提供对共享数据对象的访问。

6.套接字(socket)
可用于不同机器间进程通信

二、Linux多线程同步方式?
1.互斥量 (mutex)

#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t * mutex);
//对互斥量进行加锁
int pthread_mutex_lock(pthread_mutex_t * mutex);
int pthread_mutex_trylock(pthread_mutex_t * mutex);
int pthread_mutex_unlock(pthread_mutex_t * mutex);

2.读写锁
读写锁于互斥量类似,但是读写锁允许更高的并行性。互斥量要么是锁状态,要么是不加锁状态,而且一次只有一个线程可以对其加锁。但是,读写锁可以有3种状态:读模式下加锁状态,写模式下加锁状态,不加锁状态。一次只有一个线程可以占有写模式的读写锁,但是可以多线程可以同时占用读模式的读写锁。

#include <pthread.h>
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlock_t *restrict attr);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);

3.条件变量
条件变量给多个线程提供了一个会合的场所。条件变量与互斥变量一起使用时,允许线程以无竞争的方式等待特定条件发生。

#include <pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);

4.自旋锁
自旋锁在获取锁之前一直处于忙等(自旋)阻塞状态。自旋锁可用于以下情况:锁被持有的时间短,而且线程并不希望在重新调度上花费太多的成本。

5.屏障
屏障(barrier)是用户协调多个线程并行工作的同步机制。屏障允许每个线程等待,直到所有的合作线程都达到某一点,然后从该点继续执行。如pthread_join函数就是一种屏障,允许一个线程等待,直到另一个线程退出。

三、字符串匹配
1.朴素字符串匹配算法
2.KMP算法
http://blog.csdn.net/jun2016425/article/details/78259098

四、进程通信:共享内存
共享内存是可用IPC形式中最快的。为什么最快呢,因为一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再涉及内核。然而往该共享内存存放信息或从中取走信息的进程间通常需要某种形式的同步。
mmap

五、select、poll、epoll的区别
查看: http://www.cnblogs.com/Anker/p/3265058.html

六、写完整的Deamon进程产生的过程,以及僵尸进程如何预防,主要用到的函数。
Deamon进程产生的过程:
(1)首先要做的是调用umask将文件模式创建屏蔽字设置为一个已知值(通常是0)
(2)调用fork,然后使父进程exit.
(3)调用setsid创建一个新会话。使调用进程(a)成为一个新会话的首进程
(b)成为一个新进程组的组长进程(c)没有控制终端
(4)将当前工作目录改为根目录。
(5)关闭不再需要的文件描述符。可以使用open_max函数或getrlimit函数来判定最高文件描述符值,并关闭直到该值的所有描述符。
(6)某些守护进程打开/dev/null使其具有文件描述符0, 1和2, 这样,任何一个试图读标准输入,写标准输出或标准错误的库例程都不会产生任何效果。
预防僵尸进程产生:
如果一个进程fork一个进程,但不要它等待子进程终止, 也不希望子进程处于僵死状态直到父进程终止, 实现这一要求的诀窍就是调用fork两次, 思路, 父->子->孙, kill掉 子, 那么 孙 的父进程就是 init 进程了(因为init被编写成无论何时只要有一个子进程终止,init就会调用一个wait函数取得其终止状态,这样也就防止了再系统中塞满僵死进程。), 具体代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid;
    if ((pid = fork()) < 0)
        printf("fork error");
    else if (0 == pid){ // first child
        if ((pid = fork()) < 0)
            printf("fork error");
        else if (pid > 0)
            exit(0); // parent from second fork == first child

        /*
         * We're the second child; our parent becomes init as soon
         * as our real parent calls exit() in the statement above.
         * Here's where we'd continue execting, knowing that when
         * we're done, init will reap our status.
         * */
        sleep(2);
        printf("second child, parent pid = %ld\n", (long)getppid());
        exit(0);
    }

    if (waitpid(pid, NULL, 0) != pid) // wait for first child
        printf("waitpid error");

    /*
     * We're the parent (the original process); we continue executing,
     * knowing that we're not the parent of the second child.
     * */
    exit(0);
}

七、利用select 建立一个TCP服务器的整的过程。写出主要的关键步骤和函数。

1.accept 是在TCP的三次握手之后,还是之前。
accept是在三次握手之后,accept只是从内核中已经连接上服务器的列表中取出一个链接的动作而已。

2.什么叫僵尸进程
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
与僵尸进程相对的是孤儿进程:
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

Shell脚本

C/C++

  1. C++虚拟函数的实现机制
    参考: http://blog.csdn.net/haoel/article/details/1948051

  2. STL vector, list, map的区别,还有erase, remove的区别
    参考:http://www.cnblogs.com/virusolf/p/4323940.html
    vector: 向量 相当于一个数组,在内存中分配一块连续的内存空间进行存储
    list: 双向链表, 每一个结点都包括一个信息快Info、一个前驱指针Pre、一个后驱指针Post。可以不分配必须的内存大小方便的进行添加和删除操作。使用的是非连续的内存空间进行存储
    map: map 属于标准关联容器,使用了非常高效的平衡检索二叉树:红黑树,他的插入删除效率比其他序列容器高是因为不需要做内存拷贝和内存移动,而直接替换指向节点的指针即可

remove: vector中的remove主要用在vector中,用于将不符合要求的元素移到容器尾部,而并不删除不符合要求的元素
erase: vector中erase的作用是删除掉某个位置position或一段区域(begin, end)中的元素,减少其size,erase一般是要释放资源,真正删除元素的,

3 GetMemory的考法
参考: http://www.cnblogs.com/heiyue/archive/2011/10/24/2222799.html

void GetMemory(char *p)
{
    p = (char *)malloc(100);
}
int main(int argc, char *argv[])
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "Hello");
    return 0;
}

运行结果:程序出错(Segmentation fault)

str没有得到分配内存的地址值.
内存空间状态:首先申请了四个字节的栈空间,存放str指针,此时str的值为0,存放str的这块内存的地址值为0x0012ff7c。调用函数 GetMemory,指针P入栈,也分配了四个字节的栈空间,P被赋str的值即此时P的值也为0,存放指针P的内存地址是0x0012ff2c。然后将新开辟的100个字节的内存空间地址赋给P,此时P的值为0x00372b70。函数调用结束时str的值仍为0,str并没有得到那块100个字节的内存空间地址值!

改法一:

void GetMemory(char **p)
{
    *p = (char *)malloc(100);
}
int main(int argc, char *argv[])
{
    char *str = NULL;
    GetMemory(&str);
    strcpy(str, "hello");
    return 0;
}

str可以得到分配内存的地址值。
内存空间状态:首先申请了四个字节的栈空间,存放str指针,此时str的值为0,存放str的这块内存的地址值为0x0012ff7c。调用函数 GetMemory,指针P入栈,也分配了四个字节的栈空间,此时P是一个二级指针,存放了指针str的地址值,即P的值是0x0012ff7c,存放指针P的内存空间的地址值是0x0012ff2c。然后将新开辟的100个字节的内存空间地址值0x00372b70赋给*P,即str,所以str的值为 0x00372b70。函数返回时str的值为分配的100个字节的内存空间的地址!

改法二:

char *GetMemory()
{
    return (char *)malloc(100);
}
int main(int argc, char *argv[])
{
    char *str = NULL;
    str = GetMemory();
    strcpy(str, "hello");
    return 0;
}

数据库

MySQL为例: (因为其他数据暂时没接触-:)
创:
创表
create table t1(ename varchar(10), hiredate date, sal decimal(10, 2), deptno int(2));

删表:
drop table t1;

改表:
alter table t1 modify ename varchar(20);
alter table t1 change ename ename1 varchar(30);
(modify 和 change 的区别是, modify 不能改字段名称,而change可以改)

增字段:
alter talbe t1 add column age int(2);
删字段:
alter table t1 drop column age;
改表名:
alter table t1 rename t2;

插入记录:
insert into t1(ename, hiredate, sal, deptno)values(‘Jun’, ‘2017-09-20’, ‘5300’, 1);
或者
insert into t1 values(‘Jun’, ‘2017-09-20’, ‘5300’, 1); (只要顺序一 一对应)
不插入全部字段:
insert into t1(ename, sal)values(‘Ma’, ‘8888’);

更新记录:
update t1 set sal=10000 where ename=’Jun’;
删除记录:
delete from t1 where ename = ‘Ma’;

查询记录:
select * from t1;

select * from t1 where deptno=1;
多条件查询:
select * from t1 where deptno=1 and sal<3000;
查询排序:
select * from t1 order by sal;

如果deptno相同,则按照工资从高到低排序: (desc为降序,asc为升序,默认排序是升序)
select * from t1 order by deptno, sal desc;

查询限制:
限制只显示最上面的3条
select * from t1 order by sal limit 3;

子查询:
有表t1, 还有表dept
select * from t1 where deptno in(select deptno from dept);

MySQL 对于千万级的大表要怎么优化?
(1)优化SQL和索引
(2)加缓存, memcached, redis(两者区别参考: http://blog.chinaunix.net/uid-7374279-id-4410900.html)
(3)做主从复制或主主复制,读写分离,可以在应用层做,效率高
参考知乎: https://www.zhihu.com/question/19719997

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值