-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gdb 调试多线程死锁,gdb 调试段错误,跨域问题,面试题:N 个线程循环打印,天空卫士 面试题
- Loading branch information
Showing
15 changed files
with
620 additions
and
293 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
#+TITLE: gdb 调试多线程死锁 | ||
|
||
** 死锁示例代码 | ||
#+BEGIN_SRC c | ||
#include<pthread.h> | ||
#include<unistd.h> | ||
#include<stdio.h> | ||
|
||
void* alive_thread(void *arg) | ||
{ | ||
while(1) | ||
{ | ||
usleep(1000*1000); | ||
} | ||
} | ||
|
||
void* dead_thread(void *arg) | ||
{ | ||
pthread_mutex_t mutex; | ||
pthread_mutex_init(&mutex, NULL); | ||
usleep(1000*1000); | ||
fprintf(stderr, "timeout we will start dead lock\n"); | ||
pthread_mutex_lock(&mutex); | ||
pthread_mutex_lock(&mutex); | ||
} | ||
|
||
int main(void) | ||
{ | ||
pthread_t alive_pid; | ||
pthread_create(&alive_pid, NULL, alive_thread, NULL); | ||
pthread_t dead_pid; | ||
pthread_create(&dead_pid, NULL, dead_thread, NULL); | ||
void *ret1 = NULL; | ||
pthread_join(alive_pid, &ret1); | ||
void *ret2 = NULL; | ||
pthread_join(dead_pid, &ret2); | ||
|
||
return 0; | ||
} | ||
#+END_SRC | ||
|
||
** 编译调试 | ||
|
||
#+BEGIN_SRC bash | ||
$ gcc main.c -o main -g -lpthread | ||
$ ./main | ||
timeout we will start dead lock | ||
#+END_SRC | ||
|
||
先不要杀死该进程,打开另一个终端进行 gdb 调试 | ||
|
||
#+BEGIN_SRC bash | ||
$ ps -ef | grep main | grep -v grep | ||
root 22895 22671 0 15:30 pts/0 00:00:00 ./main | ||
$ gdb main 22895 | ||
... | ||
(gdb) info threads | ||
Id Target Id Frame | ||
3 Thread 0x7f03a291a700 (LWP 22896) "main" 0x00007f03a29da06d in nanosleep () from /lib/x86_64-linux-gnu/libc.so.6 | ||
2 Thread 0x7f03a2119700 (LWP 22897) "main" 0x00007f03a2ce789c in __lll_lock_wait () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
,* 1 Thread 0x7f03a310b700 (LWP 22895) "main" 0x00007f03a2ce2148 in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
(gdb) thread 2 | ||
[Switching to thread 2 (Thread 0x7f03a2119700 (LWP 22897))] | ||
#0 0x00007f03a2ce789c in __lll_lock_wait () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
(gdb) bt | ||
#0 0x00007f03a2ce789c in __lll_lock_wait () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
#1 0x00007f03a2ce3065 in _L_lock_858 () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
#2 0x00007f03a2ce2eba in pthread_mutex_lock () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
#3 0x000000000040084c in dead_thread () | ||
#4 0x00007f03a2ce0e9a in start_thread () from /lib/x86_64-linux-gnu/libpthread.so.0 | ||
#5 0x00007f03a2a0e36d in clone () from /lib/x86_64-linux-gnu/libc.so.6 | ||
#6 0x0000000000000000 in ?? () | ||
#+END_SRC | ||
|
||
第一个线程运行到 pthread_join,显然是主线程 | ||
第二个线程运行到 __lll_lock_wait(),显然是 dead_thread() 函数中第二个 pthread_mutex_lock(&mutex) 加锁时在等待锁。通过 thread 2 跳转到该线程,bt 查看堆栈,显然发生死锁 | ||
第三个线程运行到 nanosleep(),显然是 alive_thread() 函数中无限休眠 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#+TITLE: gdb 调试段错误 | ||
|
||
** 段错误产生原因 | ||
|
||
段错误是指非法访问内存产生的错误 | ||
|
||
*** 访问不存在的内存地址 | ||
#+BEGIN_SRC c | ||
#include<stdio.h> | ||
#include<stdlib.h> | ||
void main() | ||
{ | ||
int *ptr = NULL; | ||
*ptr = 0; | ||
} | ||
#+END_SRC | ||
|
||
*** 访问系统保护的内存地址 | ||
#+BEGIN_SRC c | ||
#include<stdio.h> | ||
#include<stdlib.h> | ||
void main() | ||
{ | ||
int *ptr = (int *)0; | ||
*ptr = 100; | ||
} | ||
#+END_SRC | ||
|
||
*** 访问只读的内存地址 | ||
#+BEGIN_SRC c | ||
#include<stdio.h> | ||
#include<stdlib.h> | ||
#include<string.h> | ||
void main() | ||
{ | ||
char *ptr = "test"; | ||
strcpy(ptr, "TEST"); | ||
} | ||
#+END_SRC | ||
|
||
*** 栈溢出 | ||
#+BEGIN_SRC c | ||
#include<stdio.h> | ||
#include<stdlib.h> | ||
void main() | ||
{ | ||
main(); | ||
} | ||
#+END_SRC | ||
|
||
** gdb 调试 | ||
*** 以栈溢出为例直接使用 gdb 调试 | ||
#+BEGIN_SRC bash | ||
$ gcc segfault.c -g -o segfault | ||
$ ./segfault | ||
Segmentation fault (core dumped) | ||
$ gdb segfault | ||
... | ||
(gdb) run # 使用 run 命令运行后,会提示段错误出现在文件中的位置,如下所示 | ||
Starting program: /home/he/Desktop/GDB/segfault | ||
|
||
Program received signal SIGSEGV, Segmentation fault. | ||
main () at segfault.c:5 | ||
5 main(); | ||
#+END_SRC | ||
|
||
*** 使用 core 文件调试段错误 | ||
#+BEGIN_SRC bash | ||
$ gcc segfault.c -g -o segfault | ||
$ ulimit -c # 显示 core 文件的大小 | ||
$ ulimit -c unlimited # 把 core 文件设为最大,只对本次有效 | ||
$ ./segfault # 运行程序生成 core 文件,设生成了 core.7963 | ||
Segmentation fault (core dumped) | ||
$ gdb segfault core.7963 | ||
... | ||
Core was generated by 'n./segfault'. | ||
Program terminated with signal 11, Segmentation fault. | ||
#0 main () at test2.c:12 | ||
12 main(); | ||
#+END_SRC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
#+TITLE: 跨域问题 | ||
|
||
参考 | ||
- [[http://www.ruanyifeng.com/blog/2016/04/cors.html][跨域资源共享 CORS 详解--阮一峰]] | ||
- [[https://segmentfault.com/a/1190000015597029][不要再问我跨域的问题了]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
#+TITLE: 面试题:N 个线程循环打印 | ||
|
||
** 问题 | ||
阿里多线程面试题 | ||
#+BEGIN_QUOTE | ||
通过 N 个线程顺序循环打印从 0 至 100,如给定 N = 3 则输出: | ||
thread0: 0 | ||
thread1: 1 | ||
thread2: 2 | ||
thread0: 3 | ||
thread1: 4 | ||
... | ||
#+END_QUOTE | ||
|
||
** 代码 | ||
#+BEGIN_SRC c | ||
#include <stdio.h> | ||
#include <semaphore.h> | ||
#include <pthread.h> | ||
|
||
#define N 7 // 线程数 | ||
#define M 101 // 打印数字的总数 | ||
|
||
sem_t sem[N]; | ||
|
||
void * func(void *arg) | ||
{ | ||
int id = (int)arg; // 线程编号 | ||
int offset = id < (M%N) ? 1 : 0; | ||
for(int i = 0; i < M/N + offset; ++i) | ||
{ | ||
sem_wait(&sem[id]); | ||
printf("thread %d: %d\n", id, i*N + id); | ||
sem_post(&sem[(id+1)%N]); // 下一个信号灯灯值加一,唤醒下一个线程 | ||
} | ||
} | ||
|
||
int main() | ||
{ | ||
sem_init(&sem[0], 0, 1); // 初始化,只有第一个信号灯中有一个访问资源 | ||
for(int i = 1; i < N; ++i) | ||
sem_init(&sem[i], 0, 0); | ||
|
||
pthread_t thread[N]; | ||
for(int i = 0; i < N; ++i) | ||
{ | ||
int arg = i; | ||
pthread_create(&thread[i], NULL, &func, (void*)arg); | ||
} | ||
|
||
for(int i = 0; i < N; ++i) | ||
pthread_join(thread[i], NULL); | ||
|
||
for(int i = 0; i < N; ++i) | ||
sem_destroy(&sem[i]); | ||
|
||
return 0; | ||
} | ||
#+END_SRC | ||
|
||
** 执行结果 | ||
#+BEGIN_SRC shell | ||
$ gcc test.c -o test -std=c99 -pthread | ||
$ ./test | ||
thread0: 0 | ||
thread1: 1 | ||
thread2: 2 | ||
thread3: 3 | ||
thread4: 4 | ||
thread5: 5 | ||
thread6: 6 | ||
thread0: 7 | ||
thread1: 8 | ||
thread2: 9 | ||
thread3: 10 | ||
thread4: 11 | ||
thread5: 12 | ||
thread6: 13 | ||
thread0: 14 | ||
... | ||
thread3: 94 | ||
thread4: 95 | ||
thread5: 96 | ||
thread6: 97 | ||
thread0: 98 | ||
thread1: 99 | ||
thread2: 100 | ||
#+END_SRC |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
|
||
- [[./ShadowsocksR.org][ShadowsocksR 配置]] | ||
- [[./redis 面试题.org][redis 面试题]] | ||
- [[./天空卫士 面试题.org][天空卫士 面试题]] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
#+TITLE: 天空卫士 面试题 | ||
|
||
* 岗位描述 | ||
[[../images/天空卫士.PNG]] | ||
|
||
* 面试题 | ||
- 如何判断一个单链表有环,设置2个指针,一个快一个满 | ||
|
||
- 二叉树先序遍历、中序遍历、后续遍历,根据2个确定一个 | ||
|
||
- 线程互斥锁、条件锁的生产者消费者 | ||
|
||
- gdb 调试全面掌握 | ||
|
||
- 排序 | ||
|
||
- 父子进程之间的最优通信方式 | ||
|
||
- 哈希 | ||
|
||
- pthread_self() pthread_... | ||
|
||
- epoll ET LT | ||
|
||
- 父进程如何获取退出状态 | ||
|
||
- 写个 Deamon | ||
|
||
- EAGAIN EINTR send recv read write | ||
|
||
- 惊群 | ||
|
||
- errno 为全局变量,为什么多线程不用加锁 | ||
在支持线程的环境中,多个线程共享进程地址空间,每个线程都有属于它自己的局部 errno 以避免一个线程干扰另一个线程。 | ||
对于 errno 应当知道两条规则。 | ||
1. 如果没有出错,则其值不会被一个例程清除。因此,仅当函数的返回值指明出错时,才检验其值。 | ||
2. 任一函数都不会将 errno 值设置为 0,在 <errno.h> 中定义的所有常量都不为 0。 | ||
|
||
- __VA_ARGS__ 是一个可变参数的宏,这个可宏是新的C99规范中新增的,目前似乎 gcc 和 VC6.0 之后的都支持(VC6.0 的编译器不支持)。宏前面加上 ## 的作用在于,当可变参数的个数为 0 时,这里的 ## 起到把前面多余的 "," 去掉的作用。 | ||
- __FILE__ 宏在预编译时会替换成当前的源文件名 | ||
- __LINE__ 宏在预编译时会替换成当前的行号 | ||
- __FUNCTION__ 宏在预编译时会替换成当前的函数名称 | ||
|
||
- recv read 返回0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters