系统编程-线程

  • 作业
  • 用代码实现汽车发动以及停车,乘客上车,售票员等功能

#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;
//司机:到站停车--->SIGINT Ctrl+c
//      关门开车--->SIGUSR1
void handleDrive(int sig)
{
    if(SIGINT==sig)
    {
        printf("到站了...\n");
        sleep(1);
        printf("司机开始停车\n");
        sleep(1);
        int ret = 0;
        ret = kill(pid,SIGUSR2);//发送信号给子进程,发送信号给售票员让她开门
        if (-1 == ret)
        {
            perror("kill");
        }
    }
    else if(SIGUSR1==sig)
    {
        printf("司机开始开车\n");
        sleep(1);
        printf("车正在跑\n");
        sleep(1);
    }
}
//管理员:开门--->SIGUSR2
void handleConductor(int sig)
{
    if(SIGUSR2==sig)
    {
        printf("售票员开门\n");
        sleep(1);
        printf("乘客上车\n");
        sleep(1);
        printf("售票员关门\n");
        sleep(1);       
        kill(getppid(),SIGUSR1);//售票员发送信号给司机开车
    }
}
int main()
{
    pid=fork();
    if(pid>0)//drive
    {
        signal(SIGINT,handleDrive);//注册信号
        signal(SIGUSR1,handleDrive);
        printf("司机等待售票员做好开车准备\n");
        while(1)
        {
            pause();
        }   
    }
    else if(pid==0)//conductor
    {
        signal(SIGINT,SIG_IGN);
        signal(SIGUSR2,handleConductor);
        sleep(1);
        //发送和一个开车信号,让其开车
        kill(getppid(),SIGUSR1);
        while(1)
        {
            pause();//有信号则返回,无信号就挂起
        }
    }
    else if(pid==-1)//创建进程失败
    {
        perror("fork");
        return -1;
    }
    return 0;
}


Paste_Image.png

线程

并发执行

  • 同时存在,同时运行.(并不是同时运行的,分给A10ms,运行完之后,则挂起,再给B10ms.由于时间很短,人为看不出来,以为是同时运行的)

时间片

创建线程

  • 编译时一定要加-pthread
  • 以下程序:测试两个线程是否同时运行
  • 是交替执行,不是并发

#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);//现在线程的属性默认为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之后将线程结束,但是main函数继续执行
    //使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂断
  1. 一个进程创建线程后,创建的线程同属于该进程,不独立于进程,共享进程的所有资源.
  2. 线程是最小的执行单元,若一个进程没有创建线程,我们既可以把它看作是进程,也可以是相当于线程,若一个进程创建线程之后,我们可以将该线程称之为主线程,一个进程可以创建多个线程,线程之间资源共享

#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;//将这个线程,5s之后结束
    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);//现在线程的属性默认为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会将该线程所属的进程挂掉,当然线程也会挂断

#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;//将这个线程,5s之后结束
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        i++;
        if(i==5)
        {
            //使用return,只能结束当前线程,exit会将该线程所属的进程挂掉,当然线程也会挂掉
            exit(1);
        }
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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);//现在线程的属性默认为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;

}


  • 没有将iData拷贝一份,而是资源共享
Paste_Image.png

参数的传递

  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);//将参数的地址传给他
    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. 将结构体传给他
#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(发送一个请求)

#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
void *thread_run(void *arg)
{
    //在线程函数中调用pthread_setcancelstate来设置
    //不同意结束线程请求,阻塞线程结束请求
    //直到线程允许接收线程结束请求
    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);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //发送一个结束线程请求给指定线程,默认情况下,线程会同意该结束线程请求,还可以设置不同意
    pthread_cancel(thread);//3秒之后让线程挂掉
    while(1)//测试是否挂掉,如果挂掉了,则会打印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)
{
    //在线程函数中调用pthread_setcancelstate来设置
    //不同意结束线程请求,阻塞线程结束请求
    //直到线程允许接收线程结束请求
    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);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束明若没有其他线程,则结束
    pthread_exit(NULL);
    while(1)//测试是否挂掉,如果挂掉了,则会打印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)
{
    //在线程函数中调用pthread_setcancelstate来设置
    //不同意结束线程请求,阻塞线程结束请求
    //直到线程允许接收线程结束请求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    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);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    //若存在主线程中,如果含有其他线程存在,则阻塞等待其他线程结束,若没有其他线程,则结束
    pthread_exit(NULL);
    while(1)//测试是否挂掉,如果挂掉了,则会打印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)
{
    //在线程函数中调用pthread_setcancelstate来设置
    //不同意结束线程请求,阻塞线程结束请求
    //直到线程允许接收线程结束请求
    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,NULL);
    while(1)
    {
        printf("this is thread_run...\n");
        sleep(1);
        break;//则执行一次,退出程序
        pthread_exit(NULL);//如果放在此处,则表示结束所属线程
    }
    return NULL;
}

int main()
{
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    sleep(3);
    while(1)//测试是否挂掉,如果挂掉了,则会打印this is main
    {
        printf("this is main...\n");
        sleep(1);
    }
    return 0;
}

Paste_Image.png

pthread_join等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值

#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);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    //等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值
    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);//现在线程的属性默认为NULL
    if(0!=ret)
    {
        printf("errno:%d,error:%s\n",ret,strerror(ret));
        return -1;
    }
    //等待线程结束,若线程在运行,则阻塞等待,若线程结束,立即返回,第一个参数:要等待的线程,第二个参数:要来获得线程的返回值
    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);//现在线程的属性默认为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线程++g_iData,如果线程A时间足够的话,则g_iData=1;B线程再执行,则变为2;
  • 若A时间片不够,虽然++了但++后的值还没有返回到g_iData里,所以B线程++后的值仍然为1
  • 如下,会出现中断的情况
Paste_Image.png
  • 解决以上情况,则定义一个原子锁
#include<pthread.h> //pthread_create()
#include<stdio.h>
#include<string.h>//strerror()
#include<errno.h> //errno
#include<stdlib.h>
pthread_mutex_t mutex; //互斥量或者称为锁
int g_iData=0;
void *thread_run(void *arg)
{
    while(1)
    {
        //使用pthread_mutex_lock和pthread_mutex_unlock
        //使它们之间的语句合成原子操作
        pthread_mutex_lock(&mutex);
        ++g_iData;
        printf("thread :data=%d\n",g_iData);
        pthread_mutex_unlock(&mutex);
    }
    return NULL;
}

int main()
{
    
    //初始化互斥量,NULL表示使用默认属性初始化该互斥量
    pthread_mutex_init(&mutex,NULL);//使用他的默认属性进行初始化
    pthread_t thread;
    int ret=0;
    ret=pthread_create(&thread,NULL,thread_run,NULL);//现在线程的属性默认为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;

}

  • 这样就不会出现中断的情况

一个线程从文件读取数据,另一个线程打印出来

  • 先通过以前的代码,在文件里写入几个同学的信息

#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

信号量(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;//读的信号量
sem_t print_sem;//显示的信号量
#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,接着往下执行,并且将该变量减1,如果等于0,则阻塞,直到该值大于0
            sem_wait(&read_sem);//此时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);//出错了,发送这个信号
                break;
            }
            else if (-1 == ret)
            {
                printf("read error:%s\n", strerror(errno));
                pthread_mutex_unlock(&mutex);
                sem_post(&print_sem);//出错了,发送这个信号
                break;
            }
            pthread_mutex_unlock(&mutex);
            sem_post(&print_sem);//出错了,发送这个信号
        }
        close(fd);
    }   

    return NULL;
}

void *print_thread(void *arg)
{
    Student *pStu = (Student *)arg;
    int i = 0;
    while (1)
    {
        //如果print_sem大于0,接着往下执行,并且将该变量减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);
        //将信号量的值加1
        sem_post(&read_sem);

    }

    return NULL;
}

int main(void)
{
    pthread_mutex_init(&mutex, NULL);
    
    sem_init(&read_sem,0,1);//对信号量的初始化,必须先读才能再显示,将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个哲学家进餐问题

  1. 创建5根筷子(5个信号量创建一组信号量)
  2. 创建5科学家
  3. 获得筷子
  4. 放下筷子
  5. 继续思考
int semop(int semid, struct sembuf *sops, unsigned nsops);

参数

  1. semid:信号集的识别码,可通过semget获取。
  2. sops:指向存储信号操作结构的数组指针,信号操作结构的原型如下
struct sembuf
{
        unsigned short sem_num; /* semaphore number */
        short sem_op; /* semaphore operation */
        short sem_flg; /* operation flags */
};

  • 这三个字段的意义分别为:
  1. sem_num:操作信号在信号集中的编号,第一个信号的编号是0。
  1. sem_op:
  • 1, 如果其值为正数,该值会加到现有的信号内含值中。
    通常用于释放所控资源的使用权;
  • 2, 如果sem_op的值为负数,而其绝对值又大于信号的现值,
    操作将会阻塞,直到信号值大于或等于sem_op的绝对值。
    通常用于获取资源的使用权;
  • 3, 如果sem_op的值为0,如果没有设置IPC_NOWAIT,
    则调用该操作的进程或者线程将暂时睡眠,直到信号量的值为0; 否则,进程或者线程不会睡眠,函数返回错误EAGAIN。
  1. sem_flg:信号操作标志,可能的选择有两种
  • 1, IPC_NOWAIT //对信号的操作不能满足时,semop()不会阻塞,
    并立即返回,同时设定错误信息。
  • 2, SEM_UNDO //程序结束时(不论正常或不正常),
    保证信号值会被重设为semop()调用前的值。
    这样做的目的在于避免程序在异常情况下结束时
    未将锁定的资源解锁,造成该资源永远锁定。
  1. nsops:信号操作结构的数量,恒大于或等于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;
    //获得信号量集的标识,若信号量集不存在则创建
    semfd=semget(0x1024,5,IPC_CREAT | 0777);//5,代表5个信号量
    if(-1==semfd)
    {   
        perror("semget");
        return -1;
    }
    //对信号集中的信号量进行赋值
    union semun sem;
    sem.val=1;
    int i=0;
    for(;i<5;i++)
    {
        if(-1==semctl(semfd,i,SETVAL,sem))
        {
            perror("semctl");
            return -1;
        }
    }
    //创建5个哲学家进程
    int iNum=0;//用来保存表示第几个科学家
    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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容