7.27线程

 

 

如何使用Makefile:

vi Makefile

目标:依赖

Tab 命令

pthread:pthread.o

gcc  pthread.c -o pthread -lpthread

sem:sem.c

gcc sem.c -o sem

直接执行make这个命令就可以编译这两个文件;

 

 

1、线程的概念:

1、线程是比进程更小的活动单元,他是进程种一个执行路径

2、线程同进程共用进程的地址空间。

 

特点:

1)创建一个线程比创建一个进程开销小了很多。

2)实现线程之间的通讯是十分方便的。因为这些线程都是共享资源的。

3)线程是一个动态的概念。是一个执行的分支,这个分支就是执行一个函数的调用,并发运行,如果这个函数

   执行完了,这个线程也结束。

4)主线程可以创建子线程。子线程的运行情况不会影响主线程,主线程会子线程。主线程结束了,退出了,子线程也会退出。

5)进程是操作系统分配资源的最小的单位,线程是调度的最小单位。

 

 

 

 

2、如何创建一个线程

 

       

1)创建一个线程

pthread_create - create a new thread

 

SYNOPSIS

        #include <pthread.h>

 

        int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

thread:参数类型pthread_t 用来保存线程的id

attr:描述的是线程的属性,如果说不需要修改线程的属性,可以设置为NULL。

void *(*start_routine) (void *): 这个表示的是一个函数指针,就是说我们这个线程执行起来之后,要做的事情,就在函数里面做//函数名代表函数的地址

void *arg:函数的参数是一个void *,如果要传参的话,把参数放在这个地方。

 

返回值:成功返回0

失败返回-1

 

线程的属性的修改:

相关属性,包含在这个结构体内:pthread_attr_t *attr

要修改属性,先调用这个初始化的函数,对这个属性结构体进行初始化:pthread_attr_init

 

 

2)线程退出(在未分离的状态下退出)

(1)可以调用这个函数:

       #include <pthread.h>

 

        void pthread_exit(void *retval);

只有一个参数,这个参数就是返回的结果,这个返回的类型可以是任意的,看你的需要来返回。

返回的结果,会给到在同一个进程里面,调用这个函数的线程:pthread_join,它就可以接收对应的结果。

 

 

(2)被取消退出:

SYNOPSIS

        #include <pthread.h>

 

        int pthread_cancel(pthread_t thread);

我们可以在主线程里面,发送一个取消信号,来取消指定的线程。thread这个参数就是我们所需要取消的线程的id。

 

在子线程里面,我们可以拒绝取消的请求。也可以使能取消的请求。

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

子线程的被取消退出示例代码:

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

#include<signal.h>

void * routin(void *arg)

{

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//不响应函数只能放在开头才有作用;

printf("llllllll\n");

printf("aksklsas\n");

printf("*******\n");

// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//放这里不能响应;

//pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);//使能函数,没有这个函数的时候默认为使能;

 

printf("############\n");

 

sleep(10);

pthread_exit(NULL);

}

int main()

{

 

pthread_t tid;

pthread_create(&tid,NULL,routin,(void *)&arg);

// sleep(1);

 

//sleep(2);

pthread_cancel(tid);//取消退出函数;

 

 

void *ret;

pthread_join(tid,&ret);

// printf("%s\n",(char *)ret);

return 0;

}

 

(3)函数的正常退出,结束。

 

 

 

3)线程退出之后,接收其结果:

SYNOPSIS

        #include <pthread.h>

        int pthread_join(pthread_t thread, void **retval);

thread:这个是我们要接收返回值的线程的ID。

**retval:这个是返回的结果。

//注意类型转换

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

void * routin(void *arg)

{

struct

{

char *buf;

int *pdata;

int *pspace;

}*args;//args为结构体指针

args=arg;//arg等效于&arg,用指针指向这个地址;

printf("%d,%d\n",*args->pdata,*args->pspace);//args是个结构体指针,*args目的是取里面成员变量的具体值;

// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

 

char *s=(void *)arg;

printf("这里是线程的打印:%s\n",s);

printf("这是线程打印\n");

char *msg="abcd";

pthread_exit((void *)msg);//在退出的时候,把结果返回给主线程;

 

}

int main()

{

char buf[32];

int data=10;

int space=100;

struct

{

char *buf;

int *pdata;

int *pspace;

}arg={buf,&data,&space};

pthread_t tid;

pthread_create(&tid,NULL,routin,(void *)&arg);//在这里函数名就代表函数的地址;

//sleep(1);

// pthread_cancel(tid);

 

 

void *ret;

pthread_join(tid,&ret);//等待子线程退出,接收结果,前提是子线程状态为未分离;

printf("%s\n",(char *)ret);

return 0;

}

 

/*类比上面理解结构体指针的用法:

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

void * routin(void *arg)

{

struct

{

char buf[20];

int pdata;

int pspace;

}*args;

args=arg;

printf("%s,%d,%d\n",args->buf,args->pdata,args->pspace);

char *s=(void *)arg;

printf("这里是线程的打印:%s\n",s);

printf("这是线程打印\n");

char *msg="abcd";

pthread_exit((void *)msg);

 

}

int main()

{

Struct

{

char buf[20];

int pdata;

int pspace;

}arg={"caobo",10,100};//结构体可以用来传多个变量

pthread_t tid;

pthread_create(&tid,NULL,(void *)routin,(void *)&arg);

void *ret;

pthread_join(tid,&ret);

printf("%s\n",(char *)ret);

return 0;

}*/

 

 

  1. 线程中信号量的使用(POSIX)

 

 

1)无名信号量:用于线程间的同步和互斥。

(1)声明并且初始化一个信号量:

 

声明一个有名信号量:sem_t  sem;

 

SYNOPSIS

        #include <semaphore.h>

        int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:指我们所需要初始化的这个信号量。

pshared :一般都是用0,表示这个信号量在一个进程里面的线程之间共享。

value:就是我们要初始化信号量的值是多少。

返回值:

成功返回0;

失败返回-1;

 

(2)初始化好了之后,就可以直接调用对应的函数进行P/V操作

SYNOPSIS

        #include <semaphore.h>

int sem_wait(sem_t *sem); 这个就是P操作,这个是阻塞型的,会一直等待有可用的资源。//注意参数取地址;

 

        int sem_trywait(sem_t *sem); 这个也是P操作,但是这个不阻塞,如果没有可用的资源就立刻返回。

 

int sem_post(sem_t *sem); 这个是V操作

 

返回值:

成功返回0;

失败返回-1;

 

(3)用完之后,销毁它。

int sem_destroy(sem_t *sem);

 

返回值:

成功返回0;

失败返回-1;

线程间信号量的操作:

 

实验现象:无换行打印26个英文字母;

#include<stdio.h>

#include<pthread.h>

#include<semaphore.h>

char ch='a';

sem_t space,data;

void *fun_add(void *arg)

{

while(1)

{

sem_wait(&space);//p操作

ch++;

sleep(1);

sem_post(&data);//v操作

if(ch=='z')

break;

}

pthread_exit(NULL);

}

 

void *fun_print(void *arg)

{

while(1)

{

sem_wait(&data);

fprintf(stderr,"%c",ch);

sem_post(&space);

if(ch=='z')

break;

}

pthread_exit(NULL);

}

int main()

{

pthread_t tid,tid1;

sem_init(&space,0,0);

sem_init(&data,0,1);

int ret=pthread_create(&tid,NULL,fun_print,NULL);

int ret1=pthread_create(&tid1,NULL,fun_add,NULL);

 

if(ret<0||ret1<0)

{

perror("creat fail");

}

pthread_join(tid,NULL);

pthread_join(tid1,NULL);

sem_destroy(&space);

sem_destroy(&data);

return 0;

}

 

2)有名信号量:用于进程间的同步和互斥。

(1)声明并且初始化一个信号量。

 

声明一个有名信号量:sem_t *sem;

 

 

        #include <fcntl.h>           /* For O_* constants */

        #include <sys/stat.h>        /* For mode constants */

        #include <semaphore.h>

 

        sem_t *sem_open(const char *name, int oflag); //这个函数是直接打开一个已经存在的信号量。

        sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);  //创建一个信号。

name:信号量的名字//如何获得?

oflag:如何打开,可以是创建的方式打开,O_CREAT | O_RDWR | O_EXCL,

如果使用这两种打开方式O_CREAT | O_EXCL,打开一个已经存在的信号量将会返回错误,就说明这个信号量已经存在了,我们直接打开就可以了。

mode:0666

value:这个代表信号量的初始值。

 

 返回值:如果成功返回的是信号量的地址。

 如果失败,有一种特殊情况,EEXIST  ( 需要包含#include <errno.h> ),这种情况说明这个信号量已经存在了,我们直接调用第一个打开函数去打开就可以了。

 

(2)初始化好了之后,就可以直接调用对应的函数进行P/V操作

SYNOPSIS

        #include <semaphore.h>

 

        int sem_wait(sem_t *sem); 这个就是P操作,这个是阻塞型的,会一直等待有可用的资源。

 

        int sem_trywait(sem_t *sem); 这个也是P操作,但是这个不阻塞,如果没有可用的资源就立刻返回。

 

int sem_post(sem_t *sem); 这个是V操作//和上面那种方式是一样的

 

返回值:

成功返回0;

失败返回-1;

 

(3)用完之后,销毁它。

int sem_close(sem_t *sem);

 

返回值:

成功返回0;

失败返回-1;

 

(4)如果想删除在文件系统里面的这个信号量节点,可以使用下面的函数:

 

int sem_unlink(const char *name);  //这个参数和上面的name是一样的。

 

 

注意有名信号量执行完后,状态也会改变,也会卡住,为了解决这个问题,捕捉ctrl+c信号,在信号函数里,删除信号量;

思路:space取0,data为1,先读出一个数据,再在另外一个程序写数据;

shm_r1.c

 

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/types.h>

#include<sys/shm.h>

#include<string.h>

 #include <fcntl.h>           /* For O_* constants */

    #include <sys/stat.h>        /* For mode constants */

      #include <semaphore.h>

#include<errno.h>

#include<signal.h>

#include<stdlib.h>

#include<unistd.h>

int bk=0;

int main()

{

pid_t pid;

key_t key;

char *shmaddr;

struct shmid_ds *ds;

char buf[20];

int semid;

key=ftok(".",2);

if(key<0)

{

perror("ftok fail");

return -1;

}

sem_t *SPACE,*DATA;

 

 

SPACE=sem_open("t",O_CREAT|O_EXCL,0666,0);

if(SPACE==SEM_FAILED)

{

SPACE = sem_open("t",O_RDWR);//注意重新打开还要接收信号量;

}

DATA=sem_open("d",O_CREAT|O_EXCL,0666,1);

 

if(DATA==SEM_FAILED)

{

DATA = sem_open("d",O_RDWR);

}

 

void fun_ctrl_c(int sig)

{

if(sig==SIGINT)

{

/* sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");*/

bk=1;

}

signal(SIGINT,SIG_DFL);

}

int shmid;

shmid=shmget(key,4096,IPC_CREAT | 0664);

if(shmid<0)

{

perror("shmget fail");

exit(-1);

}

shmaddr=shmat(shmid,NULL,0);

if((int)shmaddr==-1)

{

perror("shmat error");

 exit(-1);

}

signal(SIGINT,fun_ctrl_c);

while(1)

{

if(bk==1)

{

break;

}

sem_wait(DATA);

fprintf(stderr,"%c",*shmaddr);

sem_post(SPACE);

}

sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");

 

return 0;

}

 

Shm_w1.c

#include<stdio.h>

#include<stdlib.h>

#include<sys/ipc.h>

#include<sys/types.h>

#include<sys/shm.h>

#include<string.h>

#include<error.h>

 #include <fcntl.h>           /* For O_* constants */

    #include <sys/stat.h>        /* For mode constants */

      #include <semaphore.h>

#include<errno.h>

#include<signal.h>

#include<stdlib.h>

#include<unistd.h>

int bk=0;

int main()

{

pid_t pid;

key_t key;

char *shmaddr;

struct shmid_ds *ds;

char buf[20];

int semid;

sem_t *SPACE,*DATA;

key=ftok(".",2);

if(key<0)

{

perror("ftok fail");

return -1;

}

SPACE=sem_open("t",O_CREAT|O_EXCL,0666,0);

if(SPACE==SEM_FAILED)

{

SPACE=sem_open("t",O_RDWR);

}

DATA=sem_open("d",O_CREAT|O_EXCL,0666,1);

 

if(DATA==SEM_FAILED)

{

DATA=sem_open("d",O_RDWR);

}

void fun_ctrl_c(int sig)

{

if(sig==SIGINT)

{

/*sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");*/

bk=1;

 

 

}

kill(pid,SIGKILL);

}

int shmid;

shmid=shmget(key,4096,IPC_CREAT | 0664);

if(shmid<0)

{

perror("shmget fail");

exit(-1);

}

shmaddr=shmat(shmid,NULL,0);

if((int)shmaddr==-1)

{

perror("shmat error");

 exit(-1);

}

char *msg="0123456789";

int i=0;

signal(SIGQUIT,fun_ctrl_c);

while(1)

{

if(bk==1)

{

break;

}

sem_wait(SPACE);

memcpy(shmaddr,msg+i,1);

i=(i+1)%10;

sem_post(DATA);

}

 

sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");

return 0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

如何使用Makefile:

vi Makefile

目标:依赖

Tab 命令

pthread:pthread.o

gcc  pthread.c -o pthread -lpthread

sem:sem.c

gcc sem.c -o sem

直接执行make这个命令就可以编译这两个文件;

 

 

1、线程的概念:

1、线程是比进程更小的活动单元,他是进程种一个执行路径

2、线程同进程共用进程的地址空间。

 

特点:

1)创建一个线程比创建一个进程开销小了很多。

2)实现线程之间的通讯是十分方便的。因为这些线程都是共享资源的。

3)线程是一个动态的概念。是一个执行的分支,这个分支就是执行一个函数的调用,并发运行,如果这个函数

   执行完了,这个线程也结束。

4)主线程可以创建子线程。子线程的运行情况不会影响主线程,主线程会子线程。主线程结束了,退出了,子线程也会退出。

5)进程是操作系统分配资源的最小的单位,线程是调度的最小单位。

 

 

 

 

2、如何创建一个线程

 

       

1)创建一个线程

pthread_create - create a new thread

 

SYNOPSIS

        #include <pthread.h>

 

        int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);

thread:参数类型pthread_t 用来保存线程的id

attr:描述的是线程的属性,如果说不需要修改线程的属性,可以设置为NULL。

void *(*start_routine) (void *): 这个表示的是一个函数指针,就是说我们这个线程执行起来之后,要做的事情,就在函数里面做//函数名代表函数的地址

void *arg:函数的参数是一个void *,如果要传参的话,把参数放在这个地方。

 

返回值:成功返回0

失败返回-1

 

线程的属性的修改:

相关属性,包含在这个结构体内:pthread_attr_t *attr

要修改属性,先调用这个初始化的函数,对这个属性结构体进行初始化:pthread_attr_init

 

 

2)线程退出(在未分离的状态下退出)

(1)可以调用这个函数:

       #include <pthread.h>

 

        void pthread_exit(void *retval);

只有一个参数,这个参数就是返回的结果,这个返回的类型可以是任意的,看你的需要来返回。

返回的结果,会给到在同一个进程里面,调用这个函数的线程:pthread_join,它就可以接收对应的结果。

 

 

(2)被取消退出:

SYNOPSIS

        #include <pthread.h>

 

        int pthread_cancel(pthread_t thread);

我们可以在主线程里面,发送一个取消信号,来取消指定的线程。thread这个参数就是我们所需要取消的线程的id。

 

在子线程里面,我们可以拒绝取消的请求。也可以使能取消的请求。

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);

pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

子线程的被取消退出示例代码:

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

#include<signal.h>

void * routin(void *arg)

{

pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//不响应函数只能放在开头才有作用;

printf("llllllll\n");

printf("aksklsas\n");

printf("*******\n");

// pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//放这里不能响应;

//pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);//使能函数,没有这个函数的时候默认为使能;

 

printf("############\n");

 

sleep(10);

pthread_exit(NULL);

}

int main()

{

 

pthread_t tid;

pthread_create(&tid,NULL,routin,(void *)&arg);

// sleep(1);

 

//sleep(2);

pthread_cancel(tid);//取消退出函数;

 

 

void *ret;

pthread_join(tid,&ret);

// printf("%s\n",(char *)ret);

return 0;

}

 

(3)函数的正常退出,结束。

 

 

 

3)线程退出之后,接收其结果:

SYNOPSIS

        #include <pthread.h>

        int pthread_join(pthread_t thread, void **retval);

thread:这个是我们要接收返回值的线程的ID。

**retval:这个是返回的结果。

//注意类型转换

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

void * routin(void *arg)

{

struct

{

char *buf;

int *pdata;

int *pspace;

}*args;//args为结构体指针

args=arg;//arg等效于&arg,用指针指向这个地址;

printf("%d,%d\n",*args->pdata,*args->pspace);//args是个结构体指针,*args目的是取里面成员变量的具体值;

// pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

 

char *s=(void *)arg;

printf("这里是线程的打印:%s\n",s);

printf("这是线程打印\n");

char *msg="abcd";

pthread_exit((void *)msg);//在退出的时候,把结果返回给主线程;

 

}

int main()

{

char buf[32];

int data=10;

int space=100;

struct

{

char *buf;

int *pdata;

int *pspace;

}arg={buf,&data,&space};

pthread_t tid;

pthread_create(&tid,NULL,routin,(void *)&arg);//在这里函数名就代表函数的地址;

//sleep(1);

// pthread_cancel(tid);

 

 

void *ret;

pthread_join(tid,&ret);//等待子线程退出,接收结果,前提是子线程状态为未分离;

printf("%s\n",(char *)ret);

return 0;

}

 

/*类比上面理解结构体指针的用法:

#include<stdio.h>

#include<stdlib.h>

#include<pthread.h>

#include<string.h>

void * routin(void *arg)

{

struct

{

char buf[20];

int pdata;

int pspace;

}*args;

args=arg;

printf("%s,%d,%d\n",args->buf,args->pdata,args->pspace);

char *s=(void *)arg;

printf("这里是线程的打印:%s\n",s);

printf("这是线程打印\n");

char *msg="abcd";

pthread_exit((void *)msg);

 

}

int main()

{

Struct

{

char buf[20];

int pdata;

int pspace;

}arg={"caobo",10,100};//结构体可以用来传多个变量

pthread_t tid;

pthread_create(&tid,NULL,(void *)routin,(void *)&arg);

void *ret;

pthread_join(tid,&ret);

printf("%s\n",(char *)ret);

return 0;

}*/

 

 

  1. 线程中信号量的使用(POSIX)

 

 

1)无名信号量:用于线程间的同步和互斥。

(1)声明并且初始化一个信号量:

 

声明一个有名信号量:sem_t  sem;

 

SYNOPSIS

        #include <semaphore.h>

        int sem_init(sem_t *sem, int pshared, unsigned int value);

sem:指我们所需要初始化的这个信号量。

pshared :一般都是用0,表示这个信号量在一个进程里面的线程之间共享。

value:就是我们要初始化信号量的值是多少。

返回值:

成功返回0;

失败返回-1;

 

(2)初始化好了之后,就可以直接调用对应的函数进行P/V操作

SYNOPSIS

        #include <semaphore.h>

int sem_wait(sem_t *sem); 这个就是P操作,这个是阻塞型的,会一直等待有可用的资源。//注意参数取地址;

 

        int sem_trywait(sem_t *sem); 这个也是P操作,但是这个不阻塞,如果没有可用的资源就立刻返回。

 

int sem_post(sem_t *sem); 这个是V操作

 

返回值:

成功返回0;

失败返回-1;

 

(3)用完之后,销毁它。

int sem_destroy(sem_t *sem);

 

返回值:

成功返回0;

失败返回-1;

线程间信号量的操作:

 

实验现象:无换行打印26个英文字母;

#include<stdio.h>

#include<pthread.h>

#include<semaphore.h>

char ch='a';

sem_t space,data;

void *fun_add(void *arg)

{

while(1)

{

sem_wait(&space);//p操作

ch++;

sleep(1);

sem_post(&data);//v操作

if(ch=='z')

break;

}

pthread_exit(NULL);

}

 

void *fun_print(void *arg)

{

while(1)

{

sem_wait(&data);

fprintf(stderr,"%c",ch);

sem_post(&space);

if(ch=='z')

break;

}

pthread_exit(NULL);

}

int main()

{

pthread_t tid,tid1;

sem_init(&space,0,0);

sem_init(&data,0,1);

int ret=pthread_create(&tid,NULL,fun_print,NULL);

int ret1=pthread_create(&tid1,NULL,fun_add,NULL);

 

if(ret<0||ret1<0)

{

perror("creat fail");

}

pthread_join(tid,NULL);

pthread_join(tid1,NULL);

sem_destroy(&space);

sem_destroy(&data);

return 0;

}

 

2)有名信号量:用于进程间的同步和互斥。

(1)声明并且初始化一个信号量。

 

声明一个有名信号量:sem_t *sem;

 

 

        #include <fcntl.h>           /* For O_* constants */

        #include <sys/stat.h>        /* For mode constants */

        #include <semaphore.h>

 

        sem_t *sem_open(const char *name, int oflag); //这个函数是直接打开一个已经存在的信号量。

        sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);  //创建一个信号。

name:信号量的名字//如何获得?

oflag:如何打开,可以是创建的方式打开,O_CREAT | O_RDWR | O_EXCL,

如果使用这两种打开方式O_CREAT | O_EXCL,打开一个已经存在的信号量将会返回错误,就说明这个信号量已经存在了,我们直接打开就可以了。

mode:0666

value:这个代表信号量的初始值。

 

 返回值:如果成功返回的是信号量的地址。

 如果失败,有一种特殊情况,EEXIST  ( 需要包含#include <errno.h> ),这种情况说明这个信号量已经存在了,我们直接调用第一个打开函数去打开就可以了。

 

(2)初始化好了之后,就可以直接调用对应的函数进行P/V操作

SYNOPSIS

        #include <semaphore.h>

 

        int sem_wait(sem_t *sem); 这个就是P操作,这个是阻塞型的,会一直等待有可用的资源。

 

        int sem_trywait(sem_t *sem); 这个也是P操作,但是这个不阻塞,如果没有可用的资源就立刻返回。

 

int sem_post(sem_t *sem); 这个是V操作//和上面那种方式是一样的

 

返回值:

成功返回0;

失败返回-1;

 

(3)用完之后,销毁它。

int sem_close(sem_t *sem);

 

返回值:

成功返回0;

失败返回-1;

 

(4)如果想删除在文件系统里面的这个信号量节点,可以使用下面的函数:

 

int sem_unlink(const char *name);  //这个参数和上面的name是一样的。

 

 

注意有名信号量执行完后,状态也会改变,也会卡住,为了解决这个问题,捕捉ctrl+c信号,在信号函数里,删除信号量;

思路:space取0,data为1,先读出一个数据,再在另外一个程序写数据;

shm_r1.c

 

#include<stdio.h>

#include<sys/ipc.h>

#include<sys/types.h>

#include<sys/shm.h>

#include<string.h>

 #include <fcntl.h>           /* For O_* constants */

    #include <sys/stat.h>        /* For mode constants */

      #include <semaphore.h>

#include<errno.h>

#include<signal.h>

#include<stdlib.h>

#include<unistd.h>

int bk=0;

int main()

{

pid_t pid;

key_t key;

char *shmaddr;

struct shmid_ds *ds;

char buf[20];

int semid;

key=ftok(".",2);

if(key<0)

{

perror("ftok fail");

return -1;

}

sem_t *SPACE,*DATA;

 

 

SPACE=sem_open("t",O_CREAT|O_EXCL,0666,0);

if(SPACE==SEM_FAILED)

{

SPACE = sem_open("t",O_RDWR);//注意重新打开还要接收信号量;

}

DATA=sem_open("d",O_CREAT|O_EXCL,0666,1);

 

if(DATA==SEM_FAILED)

{

DATA = sem_open("d",O_RDWR);

}

 

void fun_ctrl_c(int sig)

{

if(sig==SIGINT)

{

/* sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");*/

bk=1;

}

signal(SIGINT,SIG_DFL);

}

int shmid;

shmid=shmget(key,4096,IPC_CREAT | 0664);

if(shmid<0)

{

perror("shmget fail");

exit(-1);

}

shmaddr=shmat(shmid,NULL,0);

if((int)shmaddr==-1)

{

perror("shmat error");

 exit(-1);

}

signal(SIGINT,fun_ctrl_c);

while(1)

{

if(bk==1)

{

break;

}

sem_wait(DATA);

fprintf(stderr,"%c",*shmaddr);

sem_post(SPACE);

}

sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");

 

return 0;

}

 

Shm_w1.c

#include<stdio.h>

#include<stdlib.h>

#include<sys/ipc.h>

#include<sys/types.h>

#include<sys/shm.h>

#include<string.h>

#include<error.h>

 #include <fcntl.h>           /* For O_* constants */

    #include <sys/stat.h>        /* For mode constants */

      #include <semaphore.h>

#include<errno.h>

#include<signal.h>

#include<stdlib.h>

#include<unistd.h>

int bk=0;

int main()

{

pid_t pid;

key_t key;

char *shmaddr;

struct shmid_ds *ds;

char buf[20];

int semid;

sem_t *SPACE,*DATA;

key=ftok(".",2);

if(key<0)

{

perror("ftok fail");

return -1;

}

SPACE=sem_open("t",O_CREAT|O_EXCL,0666,0);

if(SPACE==SEM_FAILED)

{

SPACE=sem_open("t",O_RDWR);

}

DATA=sem_open("d",O_CREAT|O_EXCL,0666,1);

 

if(DATA==SEM_FAILED)

{

DATA=sem_open("d",O_RDWR);

}

void fun_ctrl_c(int sig)

{

if(sig==SIGINT)

{

/*sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");*/

bk=1;

 

 

}

kill(pid,SIGKILL);

}

int shmid;

shmid=shmget(key,4096,IPC_CREAT | 0664);

if(shmid<0)

{

perror("shmget fail");

exit(-1);

}

shmaddr=shmat(shmid,NULL,0);

if((int)shmaddr==-1)

{

perror("shmat error");

 exit(-1);

}

char *msg="0123456789";

int i=0;

signal(SIGQUIT,fun_ctrl_c);

while(1)

{

if(bk==1)

{

break;

}

sem_wait(SPACE);

memcpy(shmaddr,msg+i,1);

i=(i+1)%10;

sem_post(DATA);

}

 

sem_close(SPACE);

sem_close(DATA);

sem_unlink("t");

sem_unlink("d");

return 0;

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_41723504/article/details/81516756