• (linux自学笔记)linux驱动并发控制、阻塞/非阻塞IO、异步通知


     原文地址:

    http://www.cnblogs.com/hebaichuanyeah/

    1.关于并发控制

    Linux 中多个进程对共享资源的并发访问,并发访问会导致竞态。

      在单 CPU范围内避免竞态的一种方法是在进入临界区之前屏蔽系统的中断。CPU一般都具备屏蔽中断和打开中断的功能,中断屏蔽将使得中断与进程之间的并发不再发生,由于Linux 内核的进程调度等操作都依赖中断来实现,内核抢占进程之间的并发也就得以避免了。

    local_irq_disable() //屏蔽中断
    ...
    critical section //临界区
    ...
    local_irq_enable() //开中断

    原子操作

    原子操作指的是在执行过程中不会被别的代码路径所中断的操作。

    原子操作驱动

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h> /* copy_to_user,copy_from_user */
    #include <linux/miscdevice.h>
    #include <linux/pci.h>
    #include <mach/map.h>
    #include <mach/regs-gpio.h>
    #include <mach/gpio-bank-m.h>
    #include <plat/gpio-cfg.h>
    
    #define LED_MAJOR 240
    //原子变量
    atomic_t atomic_led = ATOMIC_INIT(0);
    
    
    int led_open (struct inode *inode,struct file *filp)
    {
        unsigned tmp;
        //减1兼测试
        if (!atomic_dec_and_test(&atomic_led))
        {
            //加1
            atomic_inc(&atomic_led);
            return -1;
        }
    
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xffff0000;
        tmp |= 0x00001111;
        writel(tmp, S3C64XX_GPMCON);
        writel(0xffffffff, S3C64XX_GPMDAT);
        printk("<0>open led
    ");
        return 0;
    }
    
    ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
    {
        return count;
    }
    
    
    ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
    {
        char wbuf[1];
        unsigned tmp;
    
        copy_from_user(wbuf,buf,count);
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xfffffff0;
        tmp |= wbuf[0];
        writel(tmp, S3C64XX_GPMDAT);
    
        return count;
    }
    
    int led_release (struct inode *inode, struct file *filp)
    {
        atomic_inc(&atomic_led);
    
        return 0;
    }
    
    
    struct file_operations led_fops ={
        .owner = THIS_MODULE,
        .open = led_open,
        .read = led_read,
        .write = led_write,
        .release = led_release,
    
    };
    
    int __init led_init (void)
    {
        int rc;
        printk ("<0>led init
    ");
        rc = register_chrdev(LED_MAJOR,"led",&led_fops);
        if (rc <0)
        {
            printk ("<0>register %s char dev error
    ","led");
            return -1;
        }
    
        //atomic_t atomic_led = ATOMIC_INIT(0);
        //原子变量置1
        atomic_set(&atomic_led, 1);
        printk ("<0>success
    ");
        return 0;
    }
    
    void __exit led_exit (void)
    {
        unregister_chrdev(LED_MAJOR,"led");
        printk ("<0>module exit
    ");
        return ;
    }
    
    module_init(led_init);
    module_exit(led_exit);

    测试程序

    #include <fcntl.h>
    #include "stdio.h"
    #include "pthread.h"
    #include "stdlib.h"
    
    void thread_one(void)
    {
        int fd,count;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
    
    
        while((fd = open("/dev/my_led",O_RDWR))<0)
        {
            printf ("pthread_one:Open /dev/my_led file error
    ");
            //pthread_exit(0);
            sleep(1);
        }
        for(count=0;count<3;count++)
        {
            write(fd,&buf[0],1);
            sleep(1);
            write(fd,&buf[5],1);
            sleep(1);
        }
        close (fd);
    }
    
    void thread_two(void)
    {
        int fd,count;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
    
    
        while ((fd = open("/dev/my_led",O_RDWR)) < 0)
        {
            printf ("pthread_two:Open /dev/my_led file error
    ");
            //pthread_exit(0);
        sleep(1);
        }
        for(count=0;count<3;count++)
        {
            write(fd,&buf[1],1);
            sleep(1);
            write(fd,&buf[5],1);
            sleep(1);
        }
        close(fd);
    }
    
    main()
    {
        pthread_t thread_one_id,thread_two_id;
        int resurt;
        pthread_attr_t thread_one_attr,thread_two_attr;
        int thread_one_priority,thread_two_priority;
    
    
    
        thread_one_priority = 11;
        thread_two_priority = 11;
    
        pthread_attr_init(&thread_one_attr);
        pthread_attr_init(&thread_two_attr);
    
        //设置为指定调度算法
        pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED);
    
        //指定调度算法
        pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR);
        pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR);
    
        pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority);
    
        pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority);
    
        pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE);
        //sleep(1);
        if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1)
        {
            perror("ss");
            printf("thread one creat error
     %d",resurt);
            exit(1);
        }
    
    
        if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1)
        {
            printf("thread two creat error
    ");
            exit(1);
        }
    
    
    
        //sleep(1);
        pthread_join(thread_one_id, NULL);
        pthread_join(thread_two_id, NULL);
    }

    运行结果

     自旋锁

      自旋锁是一种对临界资源进行互斥手访问的典型手段。为了获得一个自旋锁,在某CPU 上运行的代码需先执行一个原子操作,该操作测试并设置(test-and-set)某个内存变量,由于它是原子操作,所以在该操作完成之前其他执行单元不可能访问这个内存变量。

    自旋锁保护临界段

        
        spinlock(&lock_led);
        if (count)/*已经打开*/
        {
            spin_unlock(&lock_led);
            return -1;
        }
    
        spin_unlock(&lock_led);

    信号量

    //获得信号量

    void down(struct semaphore * sem);

    //释放信号量

    void up(struct semaphore * sem);

     2 .关于阻塞/非阻塞IO

    阻塞和非阻塞I/O 是设备访问的两种不同模式,驱动程序可以灵活地支持用户空间对设备的这两种访问方式。

      阻塞操作是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。而非阻塞操作的进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。

    阻塞一个线程,直至另一个线程运行完。

    include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h> /* copy_to_user,copy_from_user */
    #include <linux/miscdevice.h>
    #include <linux/pci.h>
    #include <mach/map.h>
    #include <mach/regs-gpio.h>
    #include <mach/gpio-bank-m.h>
    #include <plat/gpio-cfg.h>
    #include <linux/wait.h>
    #include <linux/sched.h>
    
    #define LED_MAJOR 240
    
    struct my_queue
    {
        //定义等待列对头
        wait_queue_head_t queue_head;
        //定义自旋锁
        spinlock_t lock;
        //文件打开标志
        int file_flag;
    }led_queue;
    
    
    int led_open (struct inode *inode,struct file *filp)
    {
        unsigned tmp;
        struct my_queue * dev = &led_queue;
        //自旋锁 临界段
        spin_lock(&dev->lock);
    
        //定义等待列对
        DECLARE_WAITQUEUE(wait,current);
        //进入等待列对头
        add_wait_queue(&dev->queue_head, &wait);
        dev->file_flag--;
        spin_unlock(&dev->lock);
        while(dev->file_flag < 0)
        {
            //改变进程状态
             __set_current_state(TASK_INTERRUPTIBLE);
            //
            schedule();
        }
    
        spin_lock(&dev->lock);
        dev->file_flag = 0;
        spin_unlock(&dev->lock);
    
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xffff0000;
        tmp |= 0x00001111;
        writel(tmp, S3C64XX_GPMCON);
        writel(0xffffffff, S3C64XX_GPMDAT);
        printk("<0>open led
    ");
        //移除
        remove_wait_queue(&dev->queue_head, &wait);
        return 0;
    }
    
    ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
    {
        return count;
    }
    
    
    ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
    {
        char wbuf[1];
        unsigned tmp;
    
        copy_from_user(wbuf,buf,count);
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xfffffff0;
        tmp |= wbuf[0];
        writel(tmp, S3C64XX_GPMDAT);
        return count;
    }
    
    int led_release (struct inode *inode, struct file *filp)
    {
        struct my_queue * dev = &led_queue;
        spin_lock(&dev->lock);
        dev->file_flag = 1;
        spin_unlock(&dev->lock);
    
        wake_up_interruptible(&dev->queue_head);
    
        return 0;
    }
    
    
    struct file_operations led_fops ={
        .owner = THIS_MODULE,
        .open = led_open,
        .read = led_read,
        .write = led_write,
        .release = led_release,
    
    };
    
    int __init led_init (void)
    {
        int rc;
        struct my_queue * dev = &led_queue;
    
        printk ("<0>led init
    ");
        rc = register_chrdev(LED_MAJOR,"led",&led_fops);
        if (rc <0)
        {
            printk ("<0>register %s char dev error
    ","led");
            return -1;
        }
        //初始化列对头
        init_waitqueue_head(&dev->queue_head);
        //初始化自旋锁
        spin_lock_init(&dev->lock);
        //文件打开标志
        dev->file_flag = 1;
        printk ("<0>success
    ");
        return 0;
    }
    
    void __exit led_exit (void)
    {
        unregister_chrdev(LED_MAJOR,"led");
        printk ("<0>module exit
    ");
        return ;
    }
    
    module_init(led_init);
    module_exit(led_exit);

    非阻塞,poll轮循

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h> /* copy_to_user,copy_from_user */
    #include <linux/miscdevice.h>
    #include <linux/pci.h>
    #include <mach/map.h>
    #include <mach/regs-gpio.h>
    #include <mach/gpio-bank-m.h>
    #include <plat/gpio-cfg.h>
    #include <linux/wait.h>
    #include <linux/sched.h>
    #include <linux/poll.h>
    
    #define LED_MAJOR 240
    
    struct drive_str
    {
        //定义等待列对头
        wait_queue_head_t queue_head;
        //定义自旋锁
        spinlock_t lock;
        //文件打开标志
        int file_flag;
    }led_driver;
    
    
    int led_open (struct inode *inode,struct file *filp)
    {
        unsigned tmp;
    
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xffff0000;
        tmp |= 0x00001111;
        writel(tmp, S3C64XX_GPMCON);
        writel(0xffffffff, S3C64XX_GPMDAT);
        printk("<0>open led
    ");
        //移除
        return 0;
    }
    
    ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
    {
        struct drive_str * dev = &led_driver;
        //自旋锁 临界段
        spin_lock(&dev->lock);
        if(dev->file_flag == 0)
            return (0);
    
        dev->file_flag = 0;
        spin_unlock(&dev->lock);
        return (1);
    }
    
    
    ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
    {
        char wbuf[1];
        unsigned tmp;
    
    
    
        copy_from_user(wbuf,buf,count);
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xfffffff0;
        tmp |= wbuf[0];
        writel(tmp, S3C64XX_GPMDAT);
        return count;
    }
    
    int led_release (struct inode *inode, struct file *filp)
    {
        struct drive_str * dev = &led_driver;
    
        spin_lock(&dev->lock);
        dev->file_flag = 1;
        spin_unlock(&dev->lock);
    
        return 0;
    }
    
    static unsigned int led_poll(struct file * filp,poll_table *wait)
    {
        unsigned int mask = 0;
        struct drive_str *dev = &led_driver;
    
        poll_wait(filp, &dev->queue_head,wait);
    
        if(dev->file_flag)
        {
            mask = 1;
        }
    
        return (mask);
    }
    
    
    struct file_operations led_fops ={
        .owner = THIS_MODULE,
        .open = led_open,
        .read = led_read,
        .write = led_write,
        .release = led_release,
        .poll = led_poll,
    
    };
    
    int __init led_init (void)
    {
        int rc;
        struct drive_str * dev = &led_driver;
    
        printk ("<0>led init
    ");
        rc = register_chrdev(LED_MAJOR,"led",&led_fops);
        if (rc <0)
        {
            printk ("<0>register %s char dev error
    ","led");
            return -1;
        }
        //初始化列对头
        init_waitqueue_head(&dev->queue_head);
        //初始化自旋锁
        spin_lock_init(&dev->lock);
        //文件打开标志
        dev->file_flag = 1;
        printk ("<0>success
    ");
        return 0;
    }
    
    void __exit led_exit (void)
    {
        unregister_chrdev(LED_MAJOR,"led");
        printk ("<0>module exit
    ");
        return ;
    }
    
    module_init(led_init);
    module_exit(led_exit);

    测试程序

    #include "stdio.h"
    #include "pthread.h"
    #include "stdlib.h"
    #include <fcntl.h>
    #include "poll.h"
    
    void thread_one(void)
    {
        int fd,count,ret;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
        struct pollfd fds[1];
    
        fd = open("/dev/my_led",O_RDWR);
        fds[0].fd = fd;
        fds[0].events = POLLIN;
    
    
        if (fd < 0)
        {
            printf ("Open /dev/my_led file error
    ");
            pthread_exit(0);
        }
        if((ret = read(fd,&buf[1],1)) == 0)
        {
            ret = poll(fds,1,10000);
            if(ret == 0)
            {
                printf("time out
    ");
            printf("%u
    ",ret);
                pthread_exit(0);
    
            }
    
        }
    
        for(count=0;count<3;count++)
        {
            write(fd,&buf[0],1);
            sleep(1);
            write(fd,&buf[5],1);
            sleep(1);
        }
        close (fd);
    }
    
    void thread_two(void)
    {
        int fd,count,ret;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
        struct pollfd fds[1];
    
    
    
        fd = open("/dev/my_led",O_RDWR);
        fds[0].fd = fd;
        fds[0].events = POLLIN;
        if (fd == 1)
        {
            printf ("open /dev/my_led file error
    ");
            pthread_exit(0);
        }
    
        if((ret = read(fd,&buf[1],1)) == 0)
        {
            ret = poll(fds,1,10000);
            if(ret == 0)
            {
                printf("time out
    ");
            printf("%u
    ",ret);
                pthread_exit(0);
    
            }
    
        }
        for(count=0;count<3;count++)
        {
            write(fd,&buf[1],1);
            sleep(1);
            write(fd,&buf[5],1);
            sleep(1);
        }
        close(fd);
    }
    
    main()
    {
        pthread_t thread_one_id,thread_two_id;
        int resurt;
        pthread_attr_t thread_one_attr,thread_two_attr;
        int thread_one_priority,thread_two_priority;
    
    
    
        thread_one_priority = 11;
        thread_two_priority = 11;
    
        pthread_attr_init(&thread_one_attr);
        pthread_attr_init(&thread_two_attr);
    
        //设置为指定调度算法
        pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED);
    
        //指定调度算法
        pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR);
        pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR);
    
        pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority);
    
        pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority);
    
        pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE);
        //sleep(1);
        if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1)
        {
            printf("thread one creat error
     %d",resurt);
            exit(1);
        }
    
    
        if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1)
        {
            printf("thread two creat error
    ");
            exit(1);
        }
    
    
    
        //sleep(1);
        pthread_join(thread_one_id, NULL);
        pthread_join(thread_two_id, NULL);
    }

    3.异步通知

    使用信号进行进程间通信是UNIX 系统中的一种传统机制。在Linux系统中,异步通知使用信号来实现。

    使用异步通知,一个进程结束后发信号给另一个进程

    驱动程序:

    include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <asm/uaccess.h> /* copy_to_user,copy_from_user */
    #include <linux/miscdevice.h>
    #include <linux/pci.h>
    #include <mach/map.h>
    #include <mach/regs-gpio.h>
    #include <mach/gpio-bank-m.h>
    #include <plat/gpio-cfg.h>
    #include <linux/wait.h>
    #include <linux/sched.h>
    #include <linux/poll.h>
    #include <asm/signal.h>
    #include <asm-generic/siginfo.h>
    
    #define LED_MAJOR 240
    
    struct drive_str
    {
        struct fasync_struct * async
    }led_driver;
    
    
    
    static int led_open (struct inode *inode,struct file *filp)
    {
        unsigned tmp;
    
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xffff0000;
        tmp |= 0x00001111;
        writel(tmp, S3C64XX_GPMCON);
        writel(0xffffffff, S3C64XX_GPMDAT);
        printk("<0>open led
    ");
    
        return 0;
    }
    
    static ssize_t led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
    {
    
        return (count);
    }
    
    
    static ssize_t led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
    {
        char wbuf[1];
        unsigned tmp;
    
        copy_from_user(wbuf,buf,count);
    
        tmp = readl(S3C64XX_GPMDAT);
        tmp &= 0xfffffff0;
        tmp |= wbuf[0];
        writel(tmp, S3C64XX_GPMDAT);
        return count;
    }
    
    static int led_fasync(int fd,struct file * filp,int mode)
    {
        struct drive_str * dev = &led_driver;
        return (fasync_helper(fd,filp,mode,&dev->async));
    }
    
    static int led_release (struct inode *inode, struct file *filp)
    {
        struct drive_str * dev = &led_driver;
    
    
        kill_fasync(&dev->async,SIGIO, POLL_IN);
    
        return (0);
    
    }
    
    
    
    struct file_operations led_fops ={
        .owner = THIS_MODULE,
        .open = led_open,
        .read = led_read,
        .write = led_write,
        .release = led_release,
        .fasync = led_fasync,
    
    };
    
    static int __init led_init (void)
    {
        int rc;
        struct drive_str * dev = &led_driver;
    
        printk ("<0>led init
    ");
        rc = register_chrdev(LED_MAJOR,"led",&led_fops);
        if (rc <0)
        {
            printk ("<0>register %s char dev error
    ","led");
            return -1;
        }
    
        dev->async = NULL;
        printk ("<0>success
    ");
        return 0;
    }
    
    static void __exit led_exit (void)
    {
        unregister_chrdev(LED_MAJOR,"led");
        printk ("<0>module exit
    ");
        return ;
    }
    
    module_init(led_init);
    module_exit(led_exit);

    测试程序:

    #include "stdio.h"
    #include "pthread.h"
    #include "stdlib.h"
    #include <fcntl.h>
    #include <signal.h>
    #include <unistd.h>
    int thread_two_fd;
    
    void sign_handler(int signum);
    
    void thread_one(void)
    {
        int fd,count;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
    
    
        fd = open("/dev/my_led",O_RDWR);
        if (fd < 0)
        {
            printf ("Open /dev/my_led file error
    ");
            pthread_exit(0);
        }
        for(count=0;count<3;count++)
        {
            write(fd,&buf[0],1);
            sleep(1);
            write(fd,&buf[5],1);
            sleep(1);
        }
        close (fd);
    }
    
    void thread_two(void)
    {
        int fd,oflags;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
    
    
        fd = open("/dev/my_led",O_RDWR);
        if (fd < 0)
        {
            printf ("open /dev/my_led file error
    ");
            pthread_exit(0);
        }
        signal(SIGIO,sign_handler);
        //改变已打开文件属性
        fcntl(fd, F_SETOWN, getpid());
        oflags = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, oflags | FASYNC);
        thread_two_fd = fd;
        pause();
    
        close(fd);
    }
    
    main()
    {
        pthread_t thread_one_id,thread_two_id;
        int resurt;
        pthread_attr_t thread_one_attr,thread_two_attr;
        int thread_one_priority,thread_two_priority;
    
    
    
        thread_one_priority = 11;
        thread_two_priority = 11;
    
        pthread_attr_init(&thread_one_attr);
        pthread_attr_init(&thread_two_attr);
    
        //设置为指定调度算法
        pthread_attr_setinheritsched(&thread_one_attr, PTHREAD_EXPLICIT_SCHED);
        pthread_attr_setinheritsched(&thread_two_attr, PTHREAD_EXPLICIT_SCHED);
    
        //指定调度算法
        pthread_attr_setschedpolicy(&thread_one_attr, SCHED_RR);
        pthread_attr_setschedpolicy(&thread_two_attr, SCHED_RR);
    
        pthread_attr_setschedparam(&thread_one_attr, (struct sched_param *)&thread_one_priority);
    
        pthread_attr_setschedparam(&thread_two_attr, (struct sched_param *)&thread_two_priority);
    
        pthread_attr_setdetachstate(&thread_one_attr,PTHREAD_CREATE_JOINABLE);
        //sleep(1);
        if((resurt = pthread_create(&thread_one_id, &thread_one_attr, (void *)thread_one, NULL)) == -1)
        {
            printf("thread one creat error
     %d",resurt);
            exit(1);
        }
    
    
        if((resurt = pthread_create(&thread_two_id, &thread_two_attr, (void *)thread_two, NULL))== -1)
        {
            printf("thread two creat error
    ");
            exit(1);
        }
    
    
    
        //sleep(1);
        pthread_join(thread_one_id, NULL);
        pthread_join(thread_two_id, NULL);
    }
    void sign_handler(int signum)
    {
        int count;
        char buf[]={~0x01,~0x02,~0x04,~0x08,0x00,0xff};
    
        printf("sign_handle
    ");
        for(count=0;count<3;count++)
        {
    
            write(thread_two_fd ,&buf[1],1);
            sleep(1);
            write(thread_two_fd ,&buf[5],1);
            sleep(1);
        }
     
    }
  • 相关阅读:
    学习笔记-php图像等比例剪裁-2016.4.7
    学习日记-2016.3.31
    学习日记--2016.3.30
    I/O扩展篇(基于74HC164/74HC165)
    Visual SVN Server启动失败0x8007042a错误
    CC3000 主机驱动API介绍
    CC3000 SPI接口编程介绍
    struct和typedef struct彻底明白了
    MSP430学习笔记:UART
    DWORD类型的IP地址转换为CString字符串
  • 原文地址:https://www.cnblogs.com/hebaichuanyeah/p/3526415.html
Copyright © 2020-2023  润新知