线程学习笔记

来源:互联网 发布:数据库权限管理 编辑:程序博客网 时间: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,就会造成死锁。所以我们可以去掉一个锁就行了。

原创粉丝点击