系統(tǒng)編程-線(xiàn)程

  • 作業(yè)
  • 用代碼實(shí)現(xiàn)汽車(chē)發(fā)動(dòng)以及停車(chē),乘客上車(chē),售票員等功能

#include<stdio.h>
#include<string.h>
#include<unistd.h> //fork
#include<stdlib.h>
#include<sys/types.h>//kill()
#include<signal.h> //signal
pid_t pid=-1;
//司機(jī):到站停車(chē)--->SIGINT Ctrl+c
//      關(guān)門(mén)開(kāi)車(chē)--->SIGUSR1
void handleDrive(int sig)
{
    if(SIGINT==sig)
    {
        printf("到站了...\n");
        sleep(1);
        printf("司機(jī)開(kāi)始停車(chē)\n");
        sleep(1);
        int ret = 0;
        ret = kill(pid,SIGUSR2);//發(fā)送信號(hào)給子進(jìn)程,發(fā)送信號(hào)給售票員讓她開(kāi)門(mén)
        if (-1 == ret)
        {
            perror("kill");
        }
    }
    else if(SIGUSR1==sig)
    {
        printf("司機(jī)開(kāi)始開(kāi)車(chē)\n");
        sleep(1);
        printf("車(chē)正在跑\n");
        sleep(1);
    }
}
//管理員:開(kāi)門(mén)--->SIGUSR2
void handleConductor(int sig)
{
    if(SIGUSR2==sig)
    {
        printf("售票員開(kāi)門(mén)\n");
        sleep(1);
        printf("乘客上車(chē)\n");
        sleep(1);
        printf("售票員關(guān)門(mén)\n");
        sleep(1);       
        kill(getppid(),SIGUSR1);//售票員發(fā)送信號(hào)給司機(jī)開(kāi)車(chē)
    }
}
int main()
{
    pid=fork();
    if(pid>0)//drive
    {
        signal(SIGINT,handleDrive);//注冊(cè)信號(hào)
        signal(SIGUSR1,handleDrive);
        printf("司機(jī)等待售票員做好開(kāi)車(chē)準(zhǔn)備\n");
        while(1)
        {
            pause();
        }   
    }
    else if(pid==0)//conductor
    {
        signal(SIGINT,SIG_IGN);
        signal(SIGUSR2,handleConductor);
        sleep(1);
        //發(fā)送和一個(gè)開(kāi)車(chē)信號(hào),讓其開(kāi)車(chē)
        kill(getppid(),SIGUSR1);
        while(1)
        {
            pause();//有信號(hào)則返回,無(wú)信號(hào)就掛起
        }
    }
    else if(pid==-1)//創(chuàng)建進(jìn)程失敗
    {
        perror("fork");
        return -1;
    }
    return 0;
}


Paste_Image.png

線(xiàn)程

并發(fā)執(zhí)行

  • 同時(shí)存在,同時(shí)運(yùn)行.(并不是同時(shí)運(yùn)行的,分給A10ms,運(yùn)行完之后,則掛起,再給B10ms.由于時(shí)間很短,人為看不出來(lái),以為是同時(shí)運(yùn)行的)

時(shí)間片

創(chuàng)建線(xiàn)程

  • 編譯時(shí)一定要加-pthread
  • 以下程序:測(cè)試兩個(gè)線(xiàn)程是否同時(shí)運(yùn)行
  • 是交替執(zhí)行,不是并發(fā)

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}


Paste_Image.png
  • 5s之后將線(xiàn)程結(jié)束,但是main函數(shù)繼續(xù)執(zhí)行
    //使用return,只能結(jié)束當(dāng)前線(xiàn)程,exit會(huì)將該線(xiàn)程所屬的進(jìn)程掛掉,當(dāng)然線(xiàn)程也會(huì)掛斷
  1. 一個(gè)進(jìn)程創(chuàng)建線(xiàn)程后,創(chuàng)建的線(xiàn)程同屬于該進(jìn)程,不獨(dú)立于進(jìn)程,共享進(jìn)程的所有資源.
  2. 線(xiàn)程是最小的執(zhí)行單元,若一個(gè)進(jìn)程沒(méi)有創(chuàng)建線(xiàn)程,我們既可以把它看作是進(jìn)程,也可以是相當(dāng)于線(xiàn)程,若一個(gè)進(jìn)程創(chuàng)建線(xiàn)程之后,我們可以將該線(xiàn)程稱(chēng)之為主線(xiàn)程,一個(gè)進(jìn)程可以創(chuàng)建多個(gè)線(xiàn)程,線(xiàn)程之間資源共享

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    int i=0;//將這個(gè)線(xiàn)程,5s之后結(jié)束
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        i++;
        if(i==5)
        {
            return NULL;
        }
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}


Paste_Image.png
  • 使用exit之后,exit會(huì)將該線(xiàn)程所屬的進(jìn)程掛掉,當(dāng)然線(xiàn)程也會(huì)掛斷

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>

void *thread_run(void *arg)
{
    int i=0;//將這個(gè)線(xiàn)程,5s之后結(jié)束
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        i++;
        if(i==5)
        {
            //使用return,只能結(jié)束當(dāng)前線(xiàn)程,exit會(huì)將該線(xiàn)程所屬的進(jìn)程掛掉,當(dāng)然線(xiàn)程也會(huì)掛掉
            exit(1);
        }
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}

Paste_Image.png
  • 資源共享
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
int g_iData=999;
void *thread_run(void *arg)
{
    //while(1)
    {
        printf("this is thread_run...iData=%d\n",g_iData);
        g_iData++;
    //  sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(2);
//  while(1)
    {
        printf("this is main...iData=%d\n",g_iData);
    //  sleep(1);
    }
    return 0;

}


  • 沒(méi)有將iData拷貝一份,而是資源共享
Paste_Image.png

參數(shù)的傳遞

  1. 將地址傳給他
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
#include<unistd.h>

void *thread_run(void *arg)
{
    while(1)
    {
    printf("this is thread_run...arg=%d\n",*(int *)arg);
        printf("this is thread_run...arg=%d\n",(int)arg);
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    int iArg=1999;
    ret=pthread_create(&thread,NULL,thread_run,&iArg);//將參數(shù)的地址傳給他
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}

Paste_Image.png

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
#include<unistd.h>

void *thread_run(void *arg)
{
    while(1)
    {
    
        printf("this is thread_run...arg=%d\n",(int)arg);
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    int iArg=1999;
    pthread_create(&thread,NULL,thread_run,(void *)iArg);//或者(void *)1888效果如上
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}

Paste_Image.png
  1. 將結(jié)構(gòu)體傳給他
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
#include<unistd.h>
typedef struct Student
{
    int iId;
    char caName[32];
    float fScore;
}Student;
void *thread_run(void *arg)
{
    while(1)
    {
        Student *pStu=(Student *)arg;
        printf("id:%d,name:%s,score:%.2f\n",pStu->iId,pStu->caName,pStu->fScore);
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    int iArg=1999;
    Student stu={1001,"zhangsan",89};
    ret=pthread_create(&thread,NULL,thread_run,&stu);
//  ret=pthread_create(&thread,NULL,thread_run,(void *)stu);//這種方法不可以
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}

Paste_Image.png

pthread cancel(發(fā)送一個(gè)請(qǐng)求)

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    //在線(xiàn)程函數(shù)中調(diào)用pthread_setcancelstate來(lái)設(shè)置
    //不同意結(jié)束線(xiàn)程請(qǐng)求,阻塞線(xiàn)程結(jié)束請(qǐng)求
    //直到線(xiàn)程允許接收線(xiàn)程結(jié)束請(qǐng)求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //發(fā)送一個(gè)結(jié)束線(xiàn)程請(qǐng)求給指定線(xiàn)程,默認(rèn)情況下,線(xiàn)程會(huì)同意該結(jié)束線(xiàn)程請(qǐng)求,還可以設(shè)置不同意
    pthread_cancel(thread);//3秒之后讓線(xiàn)程掛掉
    while(1)//測(cè)試是否掛掉,如果掛掉了,則會(huì)打印this is main
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;
}

Paste_Image.png

pthread_exit

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    //在線(xiàn)程函數(shù)中調(diào)用pthread_setcancelstate來(lái)設(shè)置
    //不同意結(jié)束線(xiàn)程請(qǐng)求,阻塞線(xiàn)程結(jié)束請(qǐng)求
    //直到線(xiàn)程允許接收線(xiàn)程結(jié)束請(qǐng)求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //若存在主線(xiàn)程中,如果含有其他線(xiàn)程存在,則阻塞等待其他線(xiàn)程結(jié)束明若沒(méi)有其他線(xiàn)程,則結(jié)束
    pthread_exit(NULL);
    while(1)//測(cè)試是否掛掉,如果掛掉了,則會(huì)打印this is main
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;
}


  • 一直等待其他線(xiàn)程的結(jié)束,則退出.如果其他線(xiàn)程結(jié)束,則退出
Paste_Image.png

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    //在線(xiàn)程函數(shù)中調(diào)用pthread_setcancelstate來(lái)設(shè)置
    //不同意結(jié)束線(xiàn)程請(qǐng)求,阻塞線(xiàn)程結(jié)束請(qǐng)求
    //直到線(xiàn)程允許接收線(xiàn)程結(jié)束請(qǐng)求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        break;//則執(zhí)行一次,退出程序
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //若存在主線(xiàn)程中,如果含有其他線(xiàn)程存在,則阻塞等待其他線(xiàn)程結(jié)束,若沒(méi)有其他線(xiàn)程,則結(jié)束
    pthread_exit(NULL);
    while(1)//測(cè)試是否掛掉,如果掛掉了,則會(huì)打印this is main
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;
}


Paste_Image.png
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    //在線(xiàn)程函數(shù)中調(diào)用pthread_setcancelstate來(lái)設(shè)置
    //不同意結(jié)束線(xiàn)程請(qǐng)求,阻塞線(xiàn)程結(jié)束請(qǐng)求
    //直到線(xiàn)程允許接收線(xiàn)程結(jié)束請(qǐng)求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        break;//則執(zhí)行一次,退出程序
        pthread_exit(NULL);//如果放在此處,則表示結(jié)束所屬線(xiàn)程
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    while(1)//測(cè)試是否掛掉,如果掛掉了,則會(huì)打印this is main
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;
}

Paste_Image.png

pthread_join等待線(xiàn)程結(jié)束,若線(xiàn)程在運(yùn)行,則阻塞等待,若線(xiàn)程結(jié)束,立即返回,第一個(gè)參數(shù):要等待的線(xiàn)程,第二個(gè)參數(shù):要來(lái)獲得線(xiàn)程的返回值

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    //等待線(xiàn)程結(jié)束,若線(xiàn)程在運(yùn)行,則阻塞等待,若線(xiàn)程結(jié)束,立即返回,第一個(gè)參數(shù):要等待的線(xiàn)程,第二個(gè)參數(shù):要來(lái)獲得線(xiàn)程的返回值
    pthread_join(thread,NULL);
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}


Paste_Image.png
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        break;
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    //等待線(xiàn)程結(jié)束,若線(xiàn)程在運(yùn)行,則阻塞等待,若線(xiàn)程結(jié)束,立即返回,第一個(gè)參數(shù):要等待的線(xiàn)程,第二個(gè)參數(shù):要來(lái)獲得線(xiàn)程的返回值
    pthread_join(thread,NULL);
    while(1)
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;

}


Paste_Image.png

pthread_addNum

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
int g_iData=0;
void *thread_run(void *arg)
{
    while(1)
    {
        ++g_iData;
        printf("thread :data=%d\n",g_iData);
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        ++g_iData;
        printf("main :data=%d\n",g_iData);
    }
    return 0;

}


  • g_iData=0;A線(xiàn)程++g_iData,如果線(xiàn)程A時(shí)間足夠的話(huà),則g_iData=1;B線(xiàn)程再執(zhí)行,則變?yōu)?;
  • 若A時(shí)間片不夠,雖然++了但++后的值還沒(méi)有返回到g_iData里,所以B線(xiàn)程++后的值仍然為1
  • 如下,會(huì)出現(xiàn)中斷的情況
Paste_Image.png
  • 解決以上情況,則定義一個(gè)原子鎖
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
pthread_mutex_t mutex; //互斥量或者稱(chēng)為鎖
int g_iData=0;
void *thread_run(void *arg)
{
    while(1)
    {
        //使用pthread_mutex_lock和pthread_mutex_unlock
        //使它們之間的語(yǔ)句合成原子操作
        pthread_mutex_lock(&mutex);
        ++g_iData;
        printf("thread :data=%d\n",g_iData);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main()
{
    
    //初始化互斥量,NULL表示使用默認(rèn)屬性初始化該互斥量
    pthread_mutex_init(&mutex,NULL);//使用他的默認(rèn)屬性進(jìn)行初始化
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//現(xiàn)在線(xiàn)程的屬性默認(rèn)為NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    while(1)
    {
        pthread_mutex_lock(&mutex);
        ++g_iData;
        printf("main :data=%d\n",g_iData);
        pthread_mutex_unlock(&mutex);
    }
    return 0;

}

  • 這樣就不會(huì)出現(xiàn)中斷的情況

一個(gè)線(xiàn)程從文件讀取數(shù)據(jù),另一個(gè)線(xiàn)程打印出來(lái)

  • 先通過(guò)以前的代碼,在文件里寫(xiě)入幾個(gè)同學(xué)的信息

#include <stdio.h>
#include <unistd.h>  //write()  read()
#include <errno.h>   //errno
#include <string.h>  //strerror()
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <pthread.h> //pthread_create

pthread_mutex_t mutex;

#define NAME_LEN 32
typedef struct Student
{
    int iId;
    char caName[NAME_LEN];
    char cSex;
    float fScore;

}Student;

int myOpen(const char *pathname)
{
    int fd  = -1;
    if (NULL != pathname)
    {
        fd = open(pathname, O_RDONLY | O_CREAT
                  , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        if (-1 == fd)
        {
            printf("open error: %s\n", strerror(errno));
        }
    }
    return fd;
}

int g_iSign = 0;

void *read_thread(void *arg)
{
    int fd = -1;
    fd = myOpen("stu.info");
    if (-1 != fd)
    {
        int ret = -1;
        Student *pStu = (Student *)arg;
        while (1)
        {
            if (0 == g_iSign)
            {
                pthread_mutex_lock(&mutex);
                memset(pStu, '\0', sizeof(Student));
                ret = read(fd, pStu, sizeof(Student));
                if (0 == ret)
                {
                    printf("reached the file end\n");
                    pthread_mutex_unlock(&mutex);
                    g_iSign = 1;
                    break;
                }
                else if (-1 == ret)
                {
                    printf("read error:%s\n", strerror(errno));
                    pthread_mutex_unlock(&mutex);
                    g_iSign = 1;
                    break;
                }
                pthread_mutex_unlock(&mutex);
                g_iSign = 1;
            }
        }
        close(fd);
    }   

    return NULL;
}

void *print_thread(void *arg)
{
    Student *pStu = (Student *)arg;
    int i = 0;
    while (1)
    {
        if (1 == g_iSign)
        {
            pthread_mutex_lock(&mutex);
            if (0 == pStu->iId)
            {
                pthread_mutex_unlock(&mutex);
                break;
            }
        
            printf("id:%d, name:%s, sex:%c, score:%.1f\n"
                   , pStu->iId, pStu->caName
                   , pStu->cSex, pStu->fScore);
        
            pthread_mutex_unlock(&mutex);
            g_iSign = 0;
        }
    }

    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, NULL);

    Student stu;
    pthread_t pthr_read;
    pthread_t pthr_show;

    pthread_create(&pthr_read, NULL, read_thread, &stu);
    pthread_create(&pthr_show, NULL, print_thread, &stu);

    pthread_join(pthr_read, NULL);
    pthread_join(pthr_show, NULL);

    return 0;
}

Paste_Image.png

信號(hào)量(sem_wait)

//int sem_init();//pshared

#include <stdio.h>
#include <unistd.h>  //write()  read()
#include <errno.h>   //errno
#include <string.h>  //strerror()
/*open()*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <pthread.h> //pthread_create
#include <semaphore.h>
pthread_mutex_t mutex;
sem_t read_sem;//讀的信號(hào)量
sem_t print_sem;//顯示的信號(hào)量
#define NAME_LEN 32
typedef struct Student
{
    int iId;
    char caName[NAME_LEN];
    char cSex;
    float fScore;

}Student;

int myOpen(const char *pathname)
{
    int fd  = -1;
    if (NULL != pathname)
    {
        fd = open(pathname, O_RDONLY | O_CREAT
                  , S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        if (-1 == fd)
        {
            printf("open error: %s\n", strerror(errno));
        }
    }
    return fd;
}


void *read_thread(void *arg)
{
    int fd = -1;
    fd = myOpen("stu.info");
    if (-1 != fd)
    {
        int ret = -1;
        Student *pStu = (Student *)arg;
        while (1)
        {
            //如果read_sem大于0,接著往下執(zhí)行,并且將該變量減1,如果等于0,則阻塞,直到該值大于0
            sem_wait(&read_sem);//此時(shí)read_sem=1
            pthread_mutex_lock(&mutex);
            memset(pStu, '\0', sizeof(Student));
            ret = read(fd, pStu, sizeof(Student));
            if (0 == ret)
            {
                printf("reached the file end\n");
                pthread_mutex_unlock(&mutex);
                sem_post(&print_sem);//出錯(cuò)了,發(fā)送這個(gè)信號(hào)
                break;
            }
            else if (-1 == ret)
            {
                printf("read error:%s\n", strerror(errno));
                pthread_mutex_unlock(&mutex);
                sem_post(&print_sem);//出錯(cuò)了,發(fā)送這個(gè)信號(hào)
                break;
            }
            pthread_mutex_unlock(&mutex);
            sem_post(&print_sem);//出錯(cuò)了,發(fā)送這個(gè)信號(hào)
        }
        close(fd);
    }   

    return NULL;
}

void *print_thread(void *arg)
{
    Student *pStu = (Student *)arg;
    int i = 0;
    while (1)
    {
        //如果print_sem大于0,接著往下執(zhí)行,并且將該變量減1,如果等于0,則阻塞,直到該值大于0
        sem_wait(&print_sem);
        pthread_mutex_lock(&mutex);
        if (0 == pStu->iId)
        {
            pthread_mutex_unlock(&mutex);
            sem_post(&read_sem);
            break;
        }
        
        printf("id:%d, name:%s, sex:%c, score:%.1f\n"
                   , pStu->iId, pStu->caName
                   , pStu->cSex, pStu->fScore);
        
        pthread_mutex_unlock(&mutex);
        //將信號(hào)量的值加1
        sem_post(&read_sem);

    }

    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, NULL);
    
    sem_init(&read_sem,0,1);//對(duì)信號(hào)量的初始化,必須先讀才能再顯示,將read_sem的值置為1
    sem_init(&print_sem,0,0);//將print_sem的值置為0

    Student stu;
    pthread_t pthr_read;
    pthread_t pthr_show;

    pthread_create(&pthr_read, NULL, read_thread, &stu);
    pthread_create(&pthr_show, NULL, print_thread, &stu);

    pthread_join(pthr_read, NULL);
    pthread_join(pthr_show, NULL);

    return 0;
}


Paste_Image.png

用代碼模仿5個(gè)哲學(xué)家進(jìn)餐問(wèn)題

  1. 創(chuàng)建5根筷子(5個(gè)信號(hào)量創(chuàng)建一組信號(hào)量)
  2. 創(chuàng)建5科學(xué)家
  3. 獲得筷子
  4. 放下筷子
  5. 繼續(xù)思考
int semop(int semid, struct sembuf *sops, unsigned nsops);

參數(shù)

  1. semid:信號(hào)集的識(shí)別碼,可通過(guò)semget獲取。
  2. sops:指向存儲(chǔ)信號(hào)操作結(jié)構(gòu)的數(shù)組指針,信號(hào)操作結(jié)構(gòu)的原型如下
struct sembuf
{
        unsigned short sem_num; /* semaphore number */
        short sem_op; /* semaphore operation */
        short sem_flg; /* operation flags */
};

  • 這三個(gè)字段的意義分別為:
  1. sem_num:操作信號(hào)在信號(hào)集中的編號(hào),第一個(gè)信號(hào)的編號(hào)是0。
  1. sem_op:
  • 1, 如果其值為正數(shù),該值會(huì)加到現(xiàn)有的信號(hào)內(nèi)含值中。
    通常用于釋放所控資源的使用權(quán);
  • 2, 如果sem_op的值為負(fù)數(shù),而其絕對(duì)值又大于信號(hào)的現(xiàn)值,
    操作將會(huì)阻塞,直到信號(hào)值大于或等于sem_op的絕對(duì)值。
    通常用于獲取資源的使用權(quán);
  • 3, 如果sem_op的值為0,如果沒(méi)有設(shè)置IPC_NOWAIT,
    則調(diào)用該操作的進(jìn)程或者線(xiàn)程將暫時(shí)睡眠,直到信號(hào)量的值為0; 否則,進(jìn)程或者線(xiàn)程不會(huì)睡眠,函數(shù)返回錯(cuò)誤EAGAIN。
  1. sem_flg:信號(hào)操作標(biāo)志,可能的選擇有兩種
  • 1, IPC_NOWAIT //對(duì)信號(hào)的操作不能滿(mǎn)足時(shí),semop()不會(huì)阻塞,
    并立即返回,同時(shí)設(shè)定錯(cuò)誤信息。
  • 2, SEM_UNDO //程序結(jié)束時(shí)(不論正常或不正常),
    保證信號(hào)值會(huì)被重設(shè)為semop()調(diào)用前的值。
    這樣做的目的在于避免程序在異常情況下結(jié)束時(shí)
    未將鎖定的資源解鎖,造成該資源永遠(yuǎn)鎖定。
  1. nsops:信號(hào)操作結(jié)構(gòu)的數(shù)量,恒大于或等于1。
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <string.h>//perror()
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#include <unistd.h>
#include <stdio.h>
union semun
{
    int val;
    struct semid_ds *buf;
    unsigned short *array;
    struct seminfo *__buf;
};

void getChopsticks(int iNum,int *semfd)
{
    int iLeft=iNum;
    int iRight=(iNum+1)%5;
    struct sembuf semope[2]={{iLeft,-1,0},
                             {iRight,-1,0}};
    semop(*semfd,semope,2);//拿筷子,獲得左右兩邊的筷子

}
void putChopsticks(int iNum,int *semfd)
{
    
    int iLeft=iNum;
    int iRight=(iNum+1)%5;
    struct sembuf semope[2]={{iLeft,1,0},
                             {iRight,1,0}};
    semop(*semfd,semope,2);//拿筷子,獲得左右兩邊的筷子
}
void thinkAndEat(int iNum,int *semfd)
{
    while(1)
    {
        printf("%d say:I am thinking...\n",iNum);
        /*拿筷子吃飯*/
        getChopsticks(iNum,semfd);
        sleep(1);
        printf("%d say:I am eatting...\n",iNum);
        /*放下筷子*/
        putChopsticks(iNum,semfd);
        printf("%d say:I am puting chopsticks...\n",iNum);
        sleep(1);
    }
}
int main(void)
{
    int semfd=-1;
    //獲得信號(hào)量集的標(biāo)識(shí),若信號(hào)量集不存在則創(chuàng)建
    semfd=semget(0x1024,5,IPC_CREAT | 0777);//5,代表5個(gè)信號(hào)量
    if(-1==semfd)
    {   
        perror("semget");
        return -1;
    }
    //對(duì)信號(hào)集中的信號(hào)量進(jìn)行賦值
    union semun sem;
    sem.val=1;
    int i=0;
    for(;i<5;i++)
    {
        if(-1==semctl(semfd,i,SETVAL,sem))
        {
            perror("semctl");
            return -1;
        }
    }
    //創(chuàng)建5個(gè)哲學(xué)家進(jìn)程
    int iNum=0;//用來(lái)保存表示第幾個(gè)科學(xué)家
    pid_t pid=-1;
    for(i=0;i<4;i++)
    {
        pid=fork();
        if(pid>0)//parent
        {   
            iNum=4;
        }
        else if(pid==0)//child
        {   
            iNum=i;
            break;//
        }
        else if(pid==-1)//error
        {
            return -1;
        }
    }
    thinkAndEat(iNum,&semfd);
    return 0;
}


Paste_Image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,673評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 178,610評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 63,939評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,668評(píng)論 6 412
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 56,004評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 43,173評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,705評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,426評(píng)論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,656評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評(píng)論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,833評(píng)論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 35,247評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 36,580評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,371評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,621評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容