线程以及线程中的无名信号量以及有名信号量

1、线程的概念:
        线程是比进程更小的活动单元,他是进程中一个执行路径
        线程同进程共用进程的地址空间。
    
    特点:
    1)创建一个线程比创建一个进程开销小了很多。
    2)实现线程之间的通讯是十分方便,因为这些线程都是共享资源的。
    3)线程是一个动态的概念。是一个执行的分支,这个分支就是执行一个函数的调用,并发运行,如果这个函数执行完了,这个线程也结束。
    4)主线程可以创建子线程。子线程的运行情况不会影响主线程,主线程会影响子线程。主线程结束了退出,子线程也会退出。
    5)进程是操作系统分配资源的最小的单位,线程是调度的最小单位。

2.线程的创建步骤

    1)创建线程、

        #include <pthread.h>

        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

    2)退出线程

              1.void  pthread_exit(void *retval);
                  只有一个参数,这个参数就是返回的结果,这个返回的类型可以是任意的,看你的需要来返回。
                   返回的结果,会给到在同一个进程里面,调用这个函数的线程:pthread_join,它就可以接收对应的结果。

               2.int pthread_cancel(pthread_t thread);
                我们可以在主线程里面,发送一个取消信号,来取消指定的线程。thread这个参数就是我们所需要取消的线程的id。
                在子线程里面,我们可以拒绝取消的请求。也可以使能取消的请求。
                    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
                    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

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

    3)接收线程退出之后的结果

                int  pthread_join(pthread_t thread, void **retval);
                                thread:这个是我们要接收返回值的线程的ID。
                                 **retval:这个是返回的结果。

3、线程中信号量的使用(POSIX)
       1)无名信号量:用于线程间的同步和互斥。
                 1.声明并且初始化一个信号量:

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

                              #include <semaphore.h>

                               int sem_init(sem_t *sem, int pshared, unsigned int value);
                                             sem:指我们所需要初始化的这个信号量。
                                             pshared :一般都是用0,表示这个信号量在一个进程里面的线程之间共享。
                                              value:就是我们要初始化信号量的值是多少。
                            返回值:成功返回0,失败返回-1;

                  3.初始化好了之后,就可以直接调用对应的函数进行P/V操作
                        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;


  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:信号量的名字  “name”
                                    oflag:如何打开,可以是创建的方式打开,O_CREAT | O_RDWR | O_EXCL,
                                    如果使用这两种打开方式O_CREAT | O_EXCL,打开一个已经存在的信号量
                                    将会返回错误,就说明这个信号量已经存在了,我们直接打开就可以了。
                                     mode:0666
                                     value:这个代表信号量的初始值。

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

        (2)初始化好了之后,就可以直接调用对应的函数进行P/V操作
                       #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是一样的。

今日代码:

/*************************************************************************
    > File Name: skread.c
    > Author: csgec
    > Mail: csgec@163.com 
    > Created Time: Thu 26 Jul 2018 10:20:28 AM HKT
 ************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>
#include<errno.h>

int main()
{
    int shmid;//共享内存ID
    char *p = NULL;
    pid_t key;

    sem_t *data,*space;//声明有名信号量

    //有名信号量的创建
    data = sem_open("sem1",O_CREAT,0666,0);
    if((int)data < 0)
    {
        printf("read 已经存在创建好了的信号量1\n");
        data = sem_open("sem1",O_RDWR);
    }

    //有名信号量的创建
    space = sem_open("sem2",O_CREAT,0666,1);
    if((int)space < 0)
    {
        printf("read 已经存在创建好了的信号量2\n");
        space = sem_open("sem2",O_RDWR);
    }    

    //创建or获得这个IPC对象,这个IPC对象就是共享内存,返回的是这个共享内存的id
    key = ftok(".",22);
    if(key < 0)
    {
        perror("ftok fail");
        exit(-1);
    }

#if 0
    //创建2个信号量,不同进程就可以根据这个信号量的ID去找到这个信号量
    semid = semget(key,2,IPC_CREAT | IPC_EXCL | 0666);    
    if(semid < 0)
    {
        printf("ipc2创建信号量错误\n");
        semid = semget(key,2,0666);    
    }
    else 
    {
    //    printf("正在初始化.......\n");
        init_sem(semid,data,0);
        init_sem(semid,space,1);
    }
#endif

    //申请内存共享,返回共享内存的ID值
    shmid = shmget(key,4096,IPC_CREAT | 0666);
    if(shmid < 0)
    {
        perror("shmget fail");
        exit(-1);
    }

    p = shmat(shmid,NULL,0);//将共享内存映射到进程空间
//    memset(p,0,sizeof(char *));
    if((int)p == -1)
    {
        perror("映射内存失败");
        exit(-1);
    }

    int i=0;
    while(1)
    {
        i++;
        sem_wait(data);
        fprintf(stderr,"%c ",*p);
        if(i == 10)
        {
            printf("\n");
            i = 0;
        }
        sem_post(space);
    }
    
    sem_close(data);
    sem_close(space);
    sem_unlink("sem1");
    sem_unlink("sem2");

    return 0;
}
/

/*************************************************************************
    > File Name: skwrite.c
    > Author: csgec
    > Mail: csgec@163.com 
    > Created Time: Thu 26 Jul 2018 10:20:28 AM HKT
 ************************************************************************/

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<stdlib.h>
#include<sys/shm.h>
#include<string.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<semaphore.h>
#include<errno.h>

int main()
{
    int shmid;//共享内存ID
    char *p;
    pid_t key;

    sem_t *data,*space;//声明有名信号量

    //有名型号量的创建
    data = sem_open("sem1",O_CREAT,0666,0);
    if((int)data < 0)
    {
        printf("write 已经存在创建好了的信号量1\n");
        data = sem_open("sem1",O_RDWR);
    }

    //有名型号量的创建
    space = sem_open("sem2",O_CREAT,0666,1);
    if((int)space < 0)
    {
        printf("write 已经存在创建好了的信号量2\n");
        space = sem_open("sem2",O_RDWR);
    }    

    //创建or获得这个IPC对象,这个IPC对象就是共享内存,返回的是这个共享内存的id
    key = ftok(".",22);
    if(key < 0)
    {
        perror("ftok fail");
        exit(-1);
    }

    //申请内存共享,返回共享内存的ID值
    shmid = shmget(key,4096,IPC_CREAT | 0666);
    if(shmid < 0)
    {
        perror("shmget fail");
        exit(-1);
    }

    p = shmat(shmid,NULL,0);//将共享内存映射到进程空间
    if((int)p == -1)
    {
        perror("映射内存失败");
        exit(-1);
    }
    char *msg = "0123456789";
    int i = 0;
    while(1)
    {
        sem_wait(space);
        memcpy(p,msg+i,1);
        sleep(1);
        i = (i+1) % 10;
        sem_post(data);
    }

    sem_close(data);
    sem_close(space);

    sem_unlink("sem1");
    sem_unlink("sem2");
    return 0;
}
 

 

     

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值