线程学习笔记
来源:互联网 发布:数据库权限管理 编辑:程序博客网 时间:2024/06/05 10:24
在线程这一章节里感觉比进程更然了,进程呢一般你创建了他,他就会继承父进程,然后单独再开辟一块空间。在自己的地盘上做操作,都不会影响其他进程。而线程就不一样了,如果你使用了全局变量。他由于调度问题,你胡乱改,出现各种意想不到结果。灰常坑。。。
一下总结几个代码,记录一些坑点。。。
- 1
#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <signal.h>#include <ctype.h>#include<stdlib.h>/* 允许建立的子进程个数最大值 */#define MAX_CHILD_NUMBER 10/* 子进程睡眠时间 */#define SLEEP_INTERVAL 2int proc_number=0;/* 子进程的自编号,从0开始 */void do_something();int main(int argc, char* argv[]){ /* 子进程个数 */ int child_proc_number = MAX_CHILD_NUMBER; int i, ch; pid_t child_pid; pid_t pid[10]={0}; /* 存放每个子进程的id */ if (argc > 1) /* 命令行参数第一个参数表示子进程个数*/ { child_proc_number = atoi(argv[1]); child_proc_number= (child_proc_number > 10) ? 10 :child_proc_number;//保证最大线程为十个; } for (i=0; i<child_proc_number; i++) { /* 填写代码,建立child_proc_number个子进程要执行 * proc_number = i; * do_something(); * 父进程把子进程的id保存到pid[i] */ pid[i]=fork(); proc_number = i; if(pid[i]==0) { do_something(); exit (0); //这个应该是不可达的; } } /* 让用户选择杀死进程,数字表示杀死该进程,q退出 */ while ((ch = getchar()) != 'q') { if (isdigit(ch)) { /* 填写代码,向pid[ch-'0']发信号SIGTERM, * 杀死该子进程 */ printf("**********%d***\n",pid[ch-'0']); if(pid[ch-'0']==-1) { printf("这个进程早死了\n"); } else { signal(SIGCHLD,SIG_IGN); if(kill(pid[ch-'0'],SIGKILL)==-1) printf("失败!!!!!!!!!!!1\n"); else pid[ch-'0']=-1; } } } /* 在这里填写代码,杀死本组的所有进程 */ for (i=0; i<child_proc_number; i++) { if(pid[i]!=-1) { signal(SIGCHLD,SIG_IGN); kill(pid[ch-'0'],SIGKILL); pid[ch-'0']=-1; } } return 0;}void do_something(){ for(;;) { printf("This is process No.%d and its pid is %d\n",proc_number, getpid()); sleep(SLEEP_INTERVAL); // 主动阻塞两秒钟 }}
这个程序是叫你创建不大于10个子进程(大于是个自动设定为十个)。然后输入编号就可以杀死对应进程。这里注意一点就是如果杀死了,就把他标记为-1,避免再次kill。还有一点是如果直接调用kill会产生僵尸进程。所以在kill之前用signal(SIGCHLD,SIG_IGN);忽视掉子进程的返回,把子进程返回交给系统释放。
- 2
#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <ctype.h>#include <pthread.h>pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;#define MAX_THREAD 3 /* 线程的个数 */unsigned long long main_counter, counter[MAX_THREAD];/* unsigned long long是比long还长的整数 */void* thread_worker(void*);int main(int argc,char* argv[]){ int i, rtn, ch; int a[3];int k=0; pthread_t pthread_id[MAX_THREAD] = {0}; /* 存放线程id*/ for (i=0; i<MAX_THREAD; i++) { /* 在这里填写代码,用pthread_create建一个普通的线程, 线程id存入pthread_id[i],线程执行函数是thread_worker 并i作为参数传递给线程 */ a[k]=i; pthread_create(&pthread_id[i],NULL,thread_worker,&a[k]); k++; } do { /* 用户按一次回车执行下面的循环体一次。按q退出 */ unsigned long long sum = 0;pthread_mutex_lock(&mutex1); /* 求所有线程的counter的和 */ for (i=0; i<MAX_THREAD; i++) { /* 求所有counter的和 */ sum += counter[i]; printf("%llu ", counter[i]); } printf("%llu/%llu", main_counter, sum);pthread_mutex_unlock(&mutex1); }while ((ch = getchar()) != 'q'); return 0;}void* thread_worker(void *p){ int thread_num; /* 在这里填写代码,把main中的i的值传递给thread_num */ thread_num=*(int*)p; printf("***%d\n",thread_num); for(;;) { /* 无限循环 */ pthread_mutex_lock(&mutex1); counter[thread_num]++; /* 本线程的counter加一 */ main_counter++; /* 主counter 加一 */ pthread_mutex_unlock(&mutex1); }}/*每个线程在争夺资源,*/
这个程序就灰常有意思,坑点特别多。
第一,在主进程循环创建子线程的时候,如果我们传参只是传了i的地址。那么主线程可能会在子线程给thread_num赋值的时候就已经对i进行过多次操作了。所以我们再开一个数组把当前的i及时从在数组不同元素下表中,然后传参时传相应的数组元素地址就可以了。
第二,三个子线程都在对一个全局变量main_counter++;。我们知道,一条语句在计算机执行的时候是分为多个指令的。如果三个进程先后将main_counter的值取出来(假如三个线程都取得了的是1),先后对值进行加一操作(三个线程都将取得的1加为2),再先后把加了的值赋给main_counter(三个线程依次将2赋值给main_counter)。那么,本来是想加三次,结果少加了,那么我们可以看到main_counter的值要比三个线程之和要小。所以我们要在循环加的地方上一把锁,避免三个线程同时对main_counter进行操作;
第三,在主线程的sum对三个counter[i]累加的时候,三个线程也会是并发的,也就是说sum在加的时候只是记录了当前值。在这之后又会改变。所以main_counter比sum大。所以我们再从加到输出上一把锁,这样counter[i]和main_counter在加到输出的时候是不会变的。所以sum和main_counter就是一样的了。
- 3
#include <stdio.h>#include <sys/types.h>#include <unistd.h>#include <ctype.h>#include <pthread.h>#define LOOP_TIMES 10000/*用宏PTHREAD_MUTEX_INITIALIZER来初始化 */pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;pthread_mutex_t mutex2 = PTHREAD_MUTEX_INITIALIZER;void* thread_worker(void*);void critical_section(int thread_num, int i);int main(void){ int rtn, i; pthread_t pthread_id = 0; /* 存放子线程的id */ rtn = pthread_create(&pthread_id,NULL, thread_worker, NULL ); if(rtn != 0) { printf("pthread_create ERROR!\n"); return -1; } for (i=0; i<LOOP_TIMES; i++) { pthread_mutex_lock(&mutex1); pthread_mutex_lock(&mutex2); critical_section(1, i); pthread_mutex_unlock(&mutex2); pthread_mutex_unlock(&mutex1); } pthread_mutex_destroy(&mutex1); pthread_mutex_destroy(&mutex2); return 0;}void* thread_worker(void* p){ int i; for (i=0; i<LOOP_TIMES; i++) { pthread_mutex_lock(&mutex2); pthread_mutex_lock(&mutex1); critical_section(2, i); pthread_mutex_unlock(&mutex2); pthread_mutex_unlock(&mutex1); }}void critical_section(int thread_num, int i){ printf("Thread%d: %d\n", thread_num,i);}
这个程序制造了一个死锁,主线程如果拿到了锁1,子线程拿到了锁2。那么主线程等待锁2,子线程等待锁1,就会造成死锁。所以我们可以去掉一个锁就行了。
- 学习笔记-线程
- 线程学习笔记
- 线程学习笔记
- 线程学习笔记
- java线程学习笔记
- 内核线程学习笔记
- java线程学习笔记
- java 线程 学习笔记
- 学习笔记之多线程
- Linux线程学习笔记
- java线程学习笔记
- 【C#】线程学习笔记
- java线程学习笔记
- MFC 线程学习笔记
- c++线程学习笔记
- Java线程学习笔记
- 线程学习笔记(-)
- java线程学习笔记
- 数据结构顺序队列
- RecyclerView 复用错乱通用解法
- 为啥要var _this = this;
- hdu 6058 Kanade's sum(区间跳跃)
- git 项目url改变,本地不能pull,push问题
- 线程学习笔记
- 找出7个默森尼数。法国数学家默森尼曾提出下列公式:Mp=2^p-1。
- 希尔排序法1
- 如何用fiddler造出满意的接口返回数据
- TreeMap源码分析(jdk1.8)
- YK的书架
- Jquery中的Ajax
- JAVA面向对象的多态性
- Echarts数据可视化全解注释