Multi-Thread 4--- Lock & Conditions

本文探讨了并发编程中读写锁与条件变量的使用,通过实例展示了如何利用它们实现线程间的同步与协调,包括数据获取、更新及通知机制。同时,介绍了使用Lock和条件变量创建受限缓冲区的方法,以及在生产者消费者模型中的应用。

1. Using reading and writing lock

Reading lock can make a data be read concurrently, but block writing thread. writeLock block all other reading and writing thread.
public class LockDemo {

	private Map<String, Object> cacheData = new HashMap<String, Object>();// this is data
	private ReadWriteLock rwl = new ReentrantReadWriteLock();
	
	//this method to get data, if not in the map, we should get access to DB, need write it back to map
	public Object getData(String key){
		rwl.readLock().lock();
		try{
			Object cache = cacheData.get(key);
			if(cache == null){
				rwl.readLock().unlock();
				rwl.writeLock().lock(); //other running read thread will lock here
				try{
					if(cache == null){//use this sentanse again to make sure other thread won't wirte again,after the
									  //first thread wirte the data back.
						cache = "aaaaa"; // go to DB to get data. 
					}
				}finally{
					rwl.writeLock().unlock();	
				}
				rwl.readLock().lock();
			}
			return cache;
		}finally{
			rwl.readLock().unlock();
		}
		
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}
}

A easier way to do this is just add synchronized key word in the definition of method.

2. Conditions

condition = lock.newCondition();
condition has method like condition.await(), and condition.signal(). it has the same function as object.wait() and object.notify(). But condition is more powerful, for it can create many conditions based  on one Lock().

For example, if we want to let thread 1, run 10 times, then thread 2 run 20 times, and then thread2 run 100 times, then goes back to thread 1. to make this loop run 30 times. we can't realize it by simply using wait() and notify. we can use Lock and conditions instead.

Business.java
public class Business {

	//lock and its conditions
	private Lock lock = new ReentrantLock();
	Condition conjob1 = lock.newCondition(); //condition that job1 should start
	Condition conjob2 = lock.newCondition(); //condition that job2 should start
	Condition conjob3 = lock.newCondition(); //condition that job3 should start
	private int flag = 1;//by default, the first job start first
	
	
	//job1, the thread runs 10 times
	public void job1(){
		lock.lock();
		try{
			while(flag != 1){ //first job should wait
				conjob1.await();
			}
			for(int i=1;i<=10;i++){
				System.out.println("job 1------------- "+i);
			}
			
			//after finish job1, it should notify job2
			flag = 2;
			conjob2.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	//job2, the thread runs 20 times
	public void job2(){
		lock.lock();
		try{
			while(flag != 2){ //second job should wait
				conjob2.await();
			}
			for(int i=1;i<=20;i++){
				System.out.println("job 2------------- "+i);
			}
			//after finish job2, it should notify job3
			flag = 3;
			conjob3.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
	
	//job3, the thread runs 30 times
	public void job3(){
		lock.lock();
		try{
			while(flag != 3){ //third job should wait
				conjob3.await();
			}
			for(int i=1;i<=30;i++){
				System.out.println("job 3------------- "+i);
			}
			//after finish job1, it should notify job2
			flag = 1;
			conjob1.signal();
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			lock.unlock();
		}
	}
}

main.java
static Business business = new Business();
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Runnable run1 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job1();
				}
				
			}
		};
		//runable2
		Runnable run2 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job2();
				}
			}
		};
		
		Runnable run3 = new Runnable(){
			@Override
			public void run() {
				// TODO Auto-generated method stub
				for(int i=1;i<30;i++){
					business.job3();
				}
			}
		};
		Thread t1 = new Thread(run1);
		Thread t2 = new Thread(run2);
		Thread t3 = new Thread(run3);
		t1.start();
		t2.start();
		t3.start();
		
	}
}

2.2 using Lock and condition to create a bundedBuffer( producer and consumer model)

Producers produce tokens at a solid speed and put the token into an array, and the consumer take out a token at a time and consume it. Create such a bundebuffer so that the producer thread will wait while the array is full, and the consumer thread will also wait while the array is empty.

 class BoundedBuffer {
   final Lock lock = new ReentrantLock(); //one lock
   final Condition notFull  = lock.newCondition(); //condition to see if it's full
   final Condition notEmpty = lock.newCondition(); //condition to see if it's empty

   final Object[] items = new Object[100];
   int putptr, takeptr, count;

   public void put(Object x) throws InterruptedException {
     lock.lock();
     try {
       while (count == items.length)  //if it's full
         notFull.await();  //not full conditon doesn't apply, so it wait
       items[putptr] = x;  //if it's not full, we put this token into a place
       if (++putptr == items.length) putptr = 0; //if put pointer goes to the end, we move it to the begining
       ++count;  //after put, the total amount would increase
       notEmpty.signal(); //signal a not empty condition, if there are any, becase we put one inside, we can make it not empty
     } finally {
       lock.unlock();  //unlock() in case there are some exception thrown
     }
   }

   public Object take() throws InterruptedException {
     lock.lock();
     try {
       while (count == 0)   //if it's empty, we can't take, so we have to wait
         notEmpty.await();  // so notEmpty make us waiting here
       Object x = items[takeptr]; //otherwise ,we take one item out of the array
       if (++takeptr == items.length) takeptr = 0; //if the take point goes to the end, we move it to the front
       --count;  //after take, the total amount would decrease one
       notFull.signal(); // notify the not full condition
       return x;
     } finally {
       lock.unlock();
     }
   }
 }





/**************************************************************************** * drivers/sensors/sensor.c * * SPDX-License-Identifier: Apache-2.0 * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * &quot;License&quot;); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an &quot;AS IS&quot; BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include &lt;nuttx/config.h&gt; #include &lt;sys/types.h&gt; #include &lt;stdbool.h&gt; #include &lt;stdio.h&gt; #include &lt;string.h&gt; #include &lt;assert.h&gt; #include &lt;errno.h&gt; #include &lt;debug.h&gt; #include &lt;poll.h&gt; #include &lt;fcntl.h&gt; #include &lt;nuttx/list.h&gt; #include &lt;nuttx/kmalloc.h&gt; #include &lt;nuttx/circbuf.h&gt; #include &lt;nuttx/mutex.h&gt; #include &lt;nuttx/sensors/sensor.h&gt; #include &lt;nuttx/lib/lib.h&gt; /**************************************************************************** * Pre-processor Definitions ****************************************************************************/ /* Device naming ************************************************************/ #define ROUND_DOWN(x, y) (((x) / (y)) * (y)) #define DEVNAME_FMT &quot;/dev/uorb/sensor_%s%s%d&quot; #define DEVNAME_UNCAL &quot;_uncal&quot; #define TIMING_BUF_ESIZE (sizeof(uint32_t)) /**************************************************************************** * Private Types ****************************************************************************/ struct sensor_axis_map_s { int8_t src_x; int8_t src_y; int8_t src_z; int8_t sign_x; int8_t sign_y; int8_t sign_z; }; /* This structure describes sensor meta */ struct sensor_meta_s { size_t esize; FAR char *name; }; typedef enum sensor_role_e { SENSOR_ROLE_NONE, SENSOR_ROLE_WR, SENSOR_ROLE_RD, SENSOR_ROLE_RDWR, } sensor_role_t; /* This structure describes user info of sensor, the user may be * advertiser or subscriber */ struct sensor_user_s { /* The common info */ struct list_node node; /* Node of users list */ struct pollfd *fds; /* The poll structure of thread waiting events */ sensor_role_t role; /* The is used to indicate user&#39;s role based on open flags */ bool changed; /* This is used to indicate event happens and need to * asynchronous notify other users */ unsigned int event; /* The event of this sensor, eg: SENSOR_EVENT_FLUSH_COMPLETE. */ bool flushing; /* The is used to indicate user is flushing */ sem_t buffersem; /* Wakeup user waiting for data in circular buffer */ size_t bufferpos; /* The index of user generation in buffer */ /* The subscriber info * Support multi advertisers to subscribe their own data when they * appear in dual role */ struct sensor_ustate_s state; }; /* This structure describes the state of the upper half driver */ struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; /* The handle of lower half driver */ struct sensor_state_s state; /* The state of sensor device */ struct circbuf_s timing; /* The circular buffer of generation */ struct circbuf_s buffer; /* The circular buffer of data */ rmutex_t lock; /* Manages exclusive access to file operations */ struct list_node userlist; /* List of users */ }; /**************************************************************************** * Private Function Prototypes ****************************************************************************/ static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role); static int sensor_open(FAR struct file *filep); static int sensor_close(FAR struct file *filep); static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t buflen); static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg); static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); /**************************************************************************** * Private Data ****************************************************************************/ static const struct sensor_axis_map_s g_remap_tbl[] = { { 0, 1, 2, 1, 1, 1 }, /* P0 */ { 1, 0, 2, 1, -1, 1 }, /* P1 */ { 0, 1, 2, -1, -1, 1 }, /* P2 */ { 1, 0, 2, -1, 1, 1 }, /* P3 */ { 0, 1, 2, -1, 1, -1 }, /* P4 */ { 1, 0, 2, -1, -1, -1 }, /* P5 */ { 0, 1, 2, 1, -1, -1 }, /* P6 */ { 1, 0, 2, 1, 1, -1 }, /* P7 */ }; static const struct sensor_meta_s g_sensor_meta[] = { {0, NULL}, {sizeof(struct sensor_accel), &quot;accel&quot;}, {sizeof(struct sensor_mag), &quot;mag&quot;}, {sizeof(struct sensor_orientation), &quot;orientation&quot;}, {sizeof(struct sensor_gyro), &quot;gyro&quot;}, {sizeof(struct sensor_light), &quot;light&quot;}, {sizeof(struct sensor_baro), &quot;baro&quot;}, {sizeof(struct sensor_noise), &quot;noise&quot;}, {sizeof(struct sensor_prox), &quot;prox&quot;}, {sizeof(struct sensor_rgb), &quot;rgb&quot;}, {sizeof(struct sensor_accel), &quot;linear_accel&quot;}, {sizeof(struct sensor_rotation), &quot;rotation&quot;}, {sizeof(struct sensor_humi), &quot;humi&quot;}, {sizeof(struct sensor_temp), &quot;temp&quot;}, {sizeof(struct sensor_pm25), &quot;pm25&quot;}, {sizeof(struct sensor_pm1p0), &quot;pm1p0&quot;}, {sizeof(struct sensor_pm10), &quot;pm10&quot;}, {sizeof(struct sensor_event), &quot;motion_detect&quot;}, {sizeof(struct sensor_event), &quot;step_detector&quot;}, {sizeof(struct sensor_step_counter), &quot;step_counter&quot;}, {sizeof(struct sensor_ph), &quot;ph&quot;}, {sizeof(struct sensor_hrate), &quot;hrate&quot;}, {sizeof(struct sensor_event), &quot;tilt_detector&quot;}, {sizeof(struct sensor_event), &quot;wake_gesture&quot;}, {sizeof(struct sensor_event), &quot;glance_gesture&quot;}, {sizeof(struct sensor_event), &quot;pickup_gesture&quot;}, {sizeof(struct sensor_event), &quot;wrist_tilt&quot;}, {sizeof(struct sensor_orientation), &quot;device_orientation&quot;}, {sizeof(struct sensor_pose_6dof), &quot;pose_6dof&quot;}, {sizeof(struct sensor_gas), &quot;gas&quot;}, {sizeof(struct sensor_event), &quot;significant_motion&quot;}, {sizeof(struct sensor_hbeat), &quot;hbeat&quot;}, {sizeof(struct sensor_force), &quot;force&quot;}, {sizeof(struct sensor_hall), &quot;hall&quot;}, {sizeof(struct sensor_event), &quot;offbody_detector&quot;}, {sizeof(struct sensor_uv), &quot;uv&quot;}, {sizeof(struct sensor_angle), &quot;hinge_angle&quot;}, {sizeof(struct sensor_ir), &quot;ir&quot;}, {sizeof(struct sensor_hcho), &quot;hcho&quot;}, {sizeof(struct sensor_tvoc), &quot;tvoc&quot;}, {sizeof(struct sensor_dust), &quot;dust&quot;}, {sizeof(struct sensor_ecg), &quot;ecg&quot;}, {sizeof(struct sensor_ppgd), &quot;ppgd&quot;}, {sizeof(struct sensor_ppgq), &quot;ppgq&quot;}, {sizeof(struct sensor_impd), &quot;impd&quot;}, {sizeof(struct sensor_ots), &quot;ots&quot;}, {sizeof(struct sensor_co2), &quot;co2&quot;}, {sizeof(struct sensor_cap), &quot;cap&quot;}, {sizeof(struct sensor_eng), &quot;eng&quot;}, {sizeof(struct sensor_gnss), &quot;gnss&quot;}, {sizeof(struct sensor_gnss_satellite), &quot;gnss_satellite&quot;}, {sizeof(struct sensor_gnss_measurement), &quot;gnss_measurement&quot;}, {sizeof(struct sensor_gnss_clock), &quot;gnss_clock&quot;}, {sizeof(struct sensor_gnss_geofence_event), &quot;gnss_geofence_event&quot;}, }; static const struct file_operations g_sensor_fops = { sensor_open, /* open */ sensor_close, /* close */ sensor_read, /* read */ sensor_write, /* write */ NULL, /* seek */ sensor_ioctl, /* ioctl */ NULL, /* mmap */ NULL, /* truncate */ sensor_poll /* poll */ }; /**************************************************************************** * Private Functions ****************************************************************************/ static void sensor_lock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_lock(&amp;upper-&gt;lock); } static void sensor_unlock(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; nxrmutex_unlock(&amp;upper-&gt;lock); } static int sensor_update_interval(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t interval) { FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *tmp; uint32_t min_interval = interval; uint32_t min_latency = interval != UINT32_MAX ? user-&gt;state.latency : UINT32_MAX; int ret = 0; if (interval == user-&gt;state.interval) { return 0; } list_for_every_entry(&amp;upper-&gt;userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp-&gt;state.interval == UINT32_MAX) { continue; } if (min_interval &gt; tmp-&gt;state.interval) { min_interval = tmp-&gt;state.interval; } if (min_latency &gt; tmp-&gt;state.latency) { min_latency = tmp-&gt;state.latency; } } if (lower-&gt;ops-&gt;set_interval) { if (min_interval != UINT32_MAX &amp;&amp; min_interval != upper-&gt;state.min_interval) { uint32_t expected_interval = min_interval; ret = lower-&gt;ops-&gt;set_interval(lower, filep, &amp;min_interval); if (ret &lt; 0) { return ret; } else if (min_interval &gt; expected_interval) { return -EINVAL; } } if (min_latency == UINT32_MAX) { min_latency = 0; } if (lower-&gt;ops-&gt;batch &amp;&amp; (min_latency != upper-&gt;state.min_latency || (min_interval != upper-&gt;state.min_interval &amp;&amp; min_latency))) { ret = lower-&gt;ops-&gt;batch(lower, filep, &amp;min_latency); if (ret &gt;= 0) { upper-&gt;state.min_latency = min_latency; } } } upper-&gt;state.min_interval = min_interval; user-&gt;state.interval = interval; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static int sensor_update_latency(FAR struct file *filep, FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, uint32_t latency) { FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *tmp; uint32_t min_latency = latency; int ret = 0; if (latency == user-&gt;state.latency) { return 0; } if (user-&gt;state.interval == UINT32_MAX) { user-&gt;state.latency = latency; return 0; } if (latency &lt;= upper-&gt;state.min_latency) { goto update; } list_for_every_entry(&amp;upper-&gt;userlist, tmp, struct sensor_user_s, node) { if (tmp == user || tmp-&gt;state.interval == UINT32_MAX) { continue; } if (min_latency &gt; tmp-&gt;state.latency) { min_latency = tmp-&gt;state.latency; } } update: if (min_latency == UINT32_MAX) { min_latency = 0; } if (min_latency == upper-&gt;state.min_latency) { user-&gt;state.latency = latency; return ret; } if (lower-&gt;ops-&gt;batch) { ret = lower-&gt;ops-&gt;batch(lower, filep, &amp;min_latency); if (ret &lt; 0) { return ret; } } upper-&gt;state.min_latency = min_latency; user-&gt;state.latency = latency; sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); return ret; } static void sensor_generate_timing(FAR struct sensor_upperhalf_s *upper, unsigned long nums) { uint32_t interval = upper-&gt;state.min_interval != UINT32_MAX ? upper-&gt;state.min_interval : 1; while (nums-- &gt; 0) { upper-&gt;state.generation += interval; circbuf_overwrite(&amp;upper-&gt;timing, &amp;upper-&gt;state.generation, TIMING_BUF_ESIZE); } } static bool sensor_is_updated(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { long delta = (long long)upper-&gt;state.generation - user-&gt;state.generation; if (delta &lt;= 0) { return false; } else if (user-&gt;state.interval == UINT32_MAX) { return true; } else { /* Check whether next generation user want in buffer. * generation next generation(not published yet) * ____v_____________v * ////|//////^ | * ^ middle point * next generation user want */ return delta &gt;= user-&gt;state.interval - (upper-&gt;state.min_interval &gt;&gt; 1); } } static void sensor_catch_up(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user) { uint32_t generation; long delta; circbuf_peek(&amp;upper-&gt;timing, &amp;generation, TIMING_BUF_ESIZE); delta = (long long)generation - user-&gt;state.generation; if (delta &gt; 0) { user-&gt;bufferpos = upper-&gt;timing.tail / TIMING_BUF_ESIZE; if (user-&gt;state.interval == UINT32_MAX) { user-&gt;state.generation = generation - 1; } else { delta -= upper-&gt;state.min_interval &gt;&gt; 1; user-&gt;state.generation += ROUND_DOWN(delta, user-&gt;state.interval); } } } static ssize_t sensor_do_samples(FAR struct sensor_upperhalf_s *upper, FAR struct sensor_user_s *user, FAR char *buffer, size_t len) { uint32_t generation; ssize_t ret = 0; size_t nums; size_t pos; size_t end; sensor_catch_up(upper, user); nums = upper-&gt;timing.head / TIMING_BUF_ESIZE - user-&gt;bufferpos; if (len &lt; nums * upper-&gt;state.esize) { nums = len / upper-&gt;state.esize; } len = nums * upper-&gt;state.esize; /* Take samples continuously */ if (user-&gt;state.interval == UINT32_MAX) { if (buffer != NULL) { ret = circbuf_peekat(&amp;upper-&gt;buffer, user-&gt;bufferpos * upper-&gt;state.esize, buffer, len); } else { ret = len; } user-&gt;bufferpos += nums; circbuf_peekat(&amp;upper-&gt;timing, (user-&gt;bufferpos - 1) * TIMING_BUF_ESIZE, &amp;user-&gt;state.generation, TIMING_BUF_ESIZE); return ret; } /* Take samples one-bye-one, to determine whether a sample needed: * * If user&#39;s next generation is on the left side of middle point, * we should copy this sample for user. * next_generation(or end) * ________________v____ * timing buffer: //|//////. | * ^ middle * generation * next sample(or end) * ________________v____ * data buffer: | | * ^ * sample */ pos = user-&gt;bufferpos; end = upper-&gt;timing.head / TIMING_BUF_ESIZE; circbuf_peekat(&amp;upper-&gt;timing, pos * TIMING_BUF_ESIZE, &amp;generation, TIMING_BUF_ESIZE); while (pos++ != end) { uint32_t next_generation; long delta; if (pos * TIMING_BUF_ESIZE == upper-&gt;timing.head) { next_generation = upper-&gt;state.generation + upper-&gt;state.min_interval; } else { circbuf_peekat(&amp;upper-&gt;timing, pos * TIMING_BUF_ESIZE, &amp;next_generation, TIMING_BUF_ESIZE); } delta = next_generation + generation - ((user-&gt;state.generation + user-&gt;state.interval) &lt;&lt; 1); if (delta &gt;= 0) { if (buffer != NULL) { ret += circbuf_peekat(&amp;upper-&gt;buffer, (pos - 1) * upper-&gt;state.esize, buffer + ret, upper-&gt;state.esize); } else { ret += upper-&gt;state.esize; } user-&gt;bufferpos = pos; user-&gt;state.generation += user-&gt;state.interval; if (ret &gt;= len) { break; } } generation = next_generation; } if (pos - 1 == end &amp;&amp; sensor_is_updated(upper, user)) { generation = upper-&gt;state.generation - user-&gt;state.generation + (upper-&gt;state.min_interval &gt;&gt; 1); user-&gt;state.generation += ROUND_DOWN(generation, user-&gt;state.interval); } return ret; } static void sensor_pollnotify_one(FAR struct sensor_user_s *user, pollevent_t eventset, sensor_role_t role) { if (!(user-&gt;role &amp; role)) { return; } if (eventset == POLLPRI) { user-&gt;changed = true; } poll_notify(&amp;user-&gt;fds, 1, eventset); } static void sensor_pollnotify(FAR struct sensor_upperhalf_s *upper, pollevent_t eventset, sensor_role_t role) { FAR struct sensor_user_s *user; list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { sensor_pollnotify_one(user, eventset, role); } } static int sensor_open(FAR struct file *filep) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); user = kmm_zalloc(sizeof(struct sensor_user_s)); if (user == NULL) { ret = -ENOMEM; goto errout_with_lock; } if (lower-&gt;ops-&gt;open) { ret = lower-&gt;ops-&gt;open(lower, filep); if (ret &lt; 0) { goto errout_with_user; } } if ((filep-&gt;f_oflags &amp; O_DIRECT) == 0) { if (filep-&gt;f_oflags &amp; O_RDOK) { if (upper-&gt;state.nsubscribers == 0 &amp;&amp; lower-&gt;ops-&gt;activate) { ret = lower-&gt;ops-&gt;activate(lower, filep, true); if (ret &lt; 0) { goto errout_with_open; } } user-&gt;role |= SENSOR_ROLE_RD; upper-&gt;state.nsubscribers++; } if (filep-&gt;f_oflags &amp; O_WROK) { user-&gt;role |= SENSOR_ROLE_WR; upper-&gt;state.nadvertisers++; if (filep-&gt;f_oflags &amp; SENSOR_PERSIST) { lower-&gt;persist = true; } } } if (upper-&gt;state.generation &amp;&amp; lower-&gt;persist) { user-&gt;state.generation = upper-&gt;state.generation - 1; user-&gt;bufferpos = upper-&gt;timing.head / TIMING_BUF_ESIZE - 1; } else { user-&gt;state.generation = upper-&gt;state.generation; user-&gt;bufferpos = upper-&gt;timing.head / TIMING_BUF_ESIZE; } user-&gt;state.interval = UINT32_MAX; user-&gt;state.esize = upper-&gt;state.esize; nxsem_init(&amp;user-&gt;buffersem, 0, 0); list_add_tail(&amp;upper-&gt;userlist, &amp;user-&gt;node); /* The new user generation, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); filep-&gt;f_priv = user; goto errout_with_lock; errout_with_open: if (lower-&gt;ops-&gt;close) { lower-&gt;ops-&gt;close(lower, filep); } errout_with_user: kmm_free(user); errout_with_lock: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static int sensor_close(FAR struct file *filep) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); if (lower-&gt;ops-&gt;close) { ret = lower-&gt;ops-&gt;close(lower, filep); if (ret &lt; 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } } if ((filep-&gt;f_oflags &amp; O_DIRECT) == 0) { if (filep-&gt;f_oflags &amp; O_RDOK) { upper-&gt;state.nsubscribers--; if (upper-&gt;state.nsubscribers == 0 &amp;&amp; lower-&gt;ops-&gt;activate) { lower-&gt;ops-&gt;activate(lower, filep, false); } } if (filep-&gt;f_oflags &amp; O_WROK) { upper-&gt;state.nadvertisers--; } } list_delete(&amp;user-&gt;node); sensor_update_latency(filep, upper, user, UINT32_MAX); sensor_update_interval(filep, upper, user, UINT32_MAX); nxsem_destroy(&amp;user-&gt;buffersem); /* The user is closed, notify to other users */ sensor_pollnotify(upper, POLLPRI, SENSOR_ROLE_WR); nxrmutex_unlock(&amp;upper-&gt;lock); kmm_free(user); return ret; } static ssize_t sensor_read(FAR struct file *filep, FAR char *buffer, size_t len) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; ssize_t ret; if (!len) { return -EINVAL; } nxrmutex_lock(&amp;upper-&gt;lock); if (lower-&gt;ops-&gt;fetch) { if (buffer == NULL) { return -EINVAL; } if (!(filep-&gt;f_oflags &amp; O_NONBLOCK)) { nxrmutex_unlock(&amp;upper-&gt;lock); ret = nxsem_wait_uninterruptible(&amp;user-&gt;buffersem); if (ret &lt; 0) { return ret; } nxrmutex_lock(&amp;upper-&gt;lock); } else if (!upper-&gt;state.nsubscribers) { ret = -EAGAIN; goto out; } ret = lower-&gt;ops-&gt;fetch(lower, filep, buffer, len); } else if (circbuf_is_empty(&amp;upper-&gt;buffer)) { ret = -ENODATA; } else if (sensor_is_updated(upper, user)) { ret = sensor_do_samples(upper, user, buffer, len); } else if (lower-&gt;persist) { if (buffer == NULL) { ret = upper-&gt;state.esize; } else { /* Persistent device can get latest old data if not updated. */ ret = circbuf_peekat(&amp;upper-&gt;buffer, (user-&gt;bufferpos - 1) * upper-&gt;state.esize, buffer, upper-&gt;state.esize); } } else { ret = -ENODATA; } out: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static ssize_t sensor_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; return lower-&gt;push_event(lower-&gt;priv, buffer, buflen); } static int sensor_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; uint32_t arg1 = (uint32_t)arg; int ret = 0; switch (cmd) { case SNIOC_GET_STATE: { nxrmutex_lock(&amp;upper-&gt;lock); memcpy((FAR void *)(uintptr_t)arg, &amp;upper-&gt;state, sizeof(upper-&gt;state)); user-&gt;changed = false; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_GET_USTATE: { nxrmutex_lock(&amp;upper-&gt;lock); memcpy((FAR void *)(uintptr_t)arg, &amp;user-&gt;state, sizeof(user-&gt;state)); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SET_INTERVAL: { nxrmutex_lock(&amp;upper-&gt;lock); ret = sensor_update_interval(filep, upper, user, arg1 ? arg1 : UINT32_MAX); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_BATCH: { nxrmutex_lock(&amp;upper-&gt;lock); ret = sensor_update_latency(filep, upper, user, arg1); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SELFTEST: { if (lower-&gt;ops-&gt;selftest == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;selftest(lower, filep, arg); } break; case SNIOC_SET_CALIBVALUE: { if (lower-&gt;ops-&gt;set_calibvalue == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;set_calibvalue(lower, filep, arg); } break; case SNIOC_CALIBRATE: { if (lower-&gt;ops-&gt;calibrate == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;calibrate(lower, filep, arg); } break; case SNIOC_SET_USERPRIV: { nxrmutex_lock(&amp;upper-&gt;lock); upper-&gt;state.priv = (uint64_t)arg; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_SET_BUFFER_NUMBER: { nxrmutex_lock(&amp;upper-&gt;lock); if (!circbuf_is_init(&amp;upper-&gt;buffer)) { if (arg1 &gt;= lower-&gt;nbuffer) { lower-&gt;nbuffer = arg1; upper-&gt;state.nbuffer = arg1; } else { ret = -ERANGE; } } else { ret = -EBUSY; } nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_UPDATED: { nxrmutex_lock(&amp;upper-&gt;lock); *(FAR bool *)(uintptr_t)arg = sensor_is_updated(upper, user); nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_GET_INFO: { if (lower-&gt;ops-&gt;get_info == NULL) { ret = -ENOTSUP; break; } ret = lower-&gt;ops-&gt;get_info(lower, filep, (FAR struct sensor_device_info_s *)(uintptr_t)arg); } break; case SNIOC_GET_EVENTS: { nxrmutex_lock(&amp;upper-&gt;lock); *(FAR unsigned int *)(uintptr_t)arg = user-&gt;event; user-&gt;event = 0; user-&gt;changed = false; nxrmutex_unlock(&amp;upper-&gt;lock); } break; case SNIOC_FLUSH: { nxrmutex_lock(&amp;upper-&gt;lock); /* If the sensor is not activated, return -EINVAL. */ if (upper-&gt;state.nsubscribers == 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return -EINVAL; } if (lower-&gt;ops-&gt;flush != NULL) { /* Lower half driver will do flush in asynchronous mode, * flush will be completed until push event happened with * bytes is zero. */ ret = lower-&gt;ops-&gt;flush(lower, filep); if (ret &gt;= 0) { user-&gt;flushing = true; } } else { /* If flush is not supported, complete immediately */ user-&gt;event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user-&gt;role); } nxrmutex_unlock(&amp;upper-&gt;lock); } break; default: /* Lowerhalf driver process other cmd. */ if (lower-&gt;ops-&gt;control) { ret = lower-&gt;ops-&gt;control(lower, filep, cmd, arg); } else { ret = -ENOTTY; } break; } return ret; } static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup) { FAR struct inode *inode = filep-&gt;f_inode; FAR struct sensor_upperhalf_s *upper = inode-&gt;i_private; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user = filep-&gt;f_priv; pollevent_t eventset = 0; int semcount; int ret = 0; nxrmutex_lock(&amp;upper-&gt;lock); if (setup) { /* Don&#39;t have enough space to store fds */ if (user-&gt;fds) { ret = -ENOSPC; goto errout; } user-&gt;fds = fds; fds-&gt;priv = filep; if (lower-&gt;ops-&gt;fetch) { /* Always return POLLIN for fetch data directly(non-block) */ if (filep-&gt;f_oflags &amp; O_NONBLOCK) { eventset |= POLLIN; } else { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &gt; 0) { eventset |= POLLIN; } } } else if (sensor_is_updated(upper, user)) { eventset |= POLLIN; } if (user-&gt;changed) { eventset |= POLLPRI; } poll_notify(&amp;fds, 1, eventset); } else { user-&gt;fds = NULL; fds-&gt;priv = NULL; } errout: nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_lowerhalf_s *lower = upper-&gt;lower; FAR struct sensor_user_s *user; unsigned long envcount; int semcount; int ret; nxrmutex_lock(&amp;upper-&gt;lock); if (bytes == 0) { list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { if (user-&gt;flushing) { user-&gt;flushing = false; user-&gt;event |= SENSOR_EVENT_FLUSH_COMPLETE; sensor_pollnotify_one(user, POLLPRI, user-&gt;role); } } nxrmutex_unlock(&amp;upper-&gt;lock); return 0; } envcount = bytes / upper-&gt;state.esize; if (bytes != envcount * upper-&gt;state.esize) { nxrmutex_unlock(&amp;upper-&gt;lock); return -EINVAL; } if (!circbuf_is_init(&amp;upper-&gt;buffer)) { /* Initialize sensor buffer when data is first generated */ ret = circbuf_init(&amp;upper-&gt;buffer, NULL, lower-&gt;nbuffer * upper-&gt;state.esize); if (ret &lt; 0) { nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } ret = circbuf_init(&amp;upper-&gt;timing, NULL, lower-&gt;nbuffer * TIMING_BUF_ESIZE); if (ret &lt; 0) { circbuf_uninit(&amp;upper-&gt;buffer); nxrmutex_unlock(&amp;upper-&gt;lock); return ret; } } circbuf_overwrite(&amp;upper-&gt;buffer, data, bytes); sensor_generate_timing(upper, envcount); list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { if (sensor_is_updated(upper, user)) { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &lt; 1) { nxsem_post(&amp;user-&gt;buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } } nxrmutex_unlock(&amp;upper-&gt;lock); return bytes; } static void sensor_notify_event(FAR void *priv) { FAR struct sensor_upperhalf_s *upper = priv; FAR struct sensor_user_s *user; int semcount; nxrmutex_lock(&amp;upper-&gt;lock); list_for_every_entry(&amp;upper-&gt;userlist, user, struct sensor_user_s, node) { nxsem_get_value(&amp;user-&gt;buffersem, &amp;semcount); if (semcount &lt; 1) { nxsem_post(&amp;user-&gt;buffersem); } sensor_pollnotify_one(user, POLLIN, SENSOR_ROLE_RD); } nxrmutex_unlock(&amp;upper-&gt;lock); } /**************************************************************************** * Public Functions ****************************************************************************/ /**************************************************************************** * Name: sensor_remap_vector_raw16 * * Description: * This function remap the sensor data according to the place position on * board. The value of place is determined base on g_remap_tbl. * * Input Parameters: * in - A pointer to input data need remap. * out - A pointer to output data. * place - The place position of sensor on board, * ex:SENSOR_BODY_COORDINATE_PX * ****************************************************************************/ void sensor_remap_vector_raw16(FAR const int16_t *in, FAR int16_t *out, int place) { FAR const struct sensor_axis_map_s *remap; int16_t tmp[3]; DEBUGASSERT(place &lt; (sizeof(g_remap_tbl) / sizeof(g_remap_tbl[0]))); remap = &amp;g_remap_tbl[place]; tmp[0] = in[remap-&gt;src_x] * remap-&gt;sign_x; tmp[1] = in[remap-&gt;src_y] * remap-&gt;sign_y; tmp[2] = in[remap-&gt;src_z] * remap-&gt;sign_z; memcpy(out, tmp, sizeof(tmp)); } /**************************************************************************** * Name: sensor_register * * Description: * This function binds an instance of a &quot;lower half&quot; Sensor driver with the * &quot;upper half&quot; Sensor device and registers that device so that can be used * by application code. * * We will register the chararter device by node name format based on the * type of sensor. Multiple types of the same type are distinguished by * numbers. eg: accel0, accel1 * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. If the * devno alerady exists, -EEXIST will be returned. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; int ret; DEBUGASSERT(lower != NULL); path = lib_get_pathbuffer(); if (path == NULL) { return -ENOMEM; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower-&gt;type].name, lower-&gt;uncalibrated ? DEVNAME_UNCAL : &quot;&quot;, devno); ret = sensor_custom_register(lower, path, g_sensor_meta[lower-&gt;type].esize); lib_put_pathbuffer(path); return ret; } /**************************************************************************** * Name: sensor_custom_register * * Description: * This function binds an instance of a &quot;lower half&quot; Sensor driver with the * &quot;upper half&quot; Sensor device and registers that device so that can be used * by application code. * * You can register the character device type by specific path and esize. * This API corresponds to the sensor_custom_unregister. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device. ex: /dev/uorb/xxx. * esize - The element size of intermediate circular buffer. * * Returned Value: * OK if the driver was successfully register; A negated errno value is * returned on any failure. * ****************************************************************************/ int sensor_custom_register(FAR struct sensor_lowerhalf_s *lower, FAR const char *path, size_t esize) { FAR struct sensor_upperhalf_s *upper; int ret = -EINVAL; DEBUGASSERT(lower != NULL); if (lower-&gt;type &gt;= SENSOR_TYPE_COUNT || !esize) { snerr(&quot;ERROR: type is invalid\n&quot;); return ret; } /* Allocate the upper-half data structure */ upper = kmm_zalloc(sizeof(struct sensor_upperhalf_s)); if (!upper) { snerr(&quot;ERROR: Allocation failed\n&quot;); return -ENOMEM; } /* Initialize the upper-half data structure */ list_initialize(&amp;upper-&gt;userlist); upper-&gt;state.esize = esize; upper-&gt;state.min_interval = UINT32_MAX; if (lower-&gt;ops-&gt;activate) { upper-&gt;state.nadvertisers = 1; } nxrmutex_init(&amp;upper-&gt;lock); /* Bind the lower half data structure member */ lower-&gt;priv = upper; lower-&gt;sensor_lock = sensor_lock; lower-&gt;sensor_unlock = sensor_unlock; if (!lower-&gt;ops-&gt;fetch) { if (!lower-&gt;nbuffer) { lower-&gt;nbuffer = 1; } lower-&gt;push_event = sensor_push_event; } else { lower-&gt;notify_event = sensor_notify_event; lower-&gt;nbuffer = 0; } #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); if (lower == NULL) { ret = -EIO; goto rpmsg_err; } #endif upper-&gt;state.nbuffer = lower-&gt;nbuffer; upper-&gt;lower = lower; sninfo(&quot;Registering %s\n&quot;, path); ret = register_driver(path, &amp;g_sensor_fops, 0666, upper); if (ret) { goto drv_err; } return ret; drv_err: #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); rpmsg_err: #endif nxrmutex_destroy(&amp;upper-&gt;lock); kmm_free(upper); return ret; } /**************************************************************************** * Name: sensor_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * devno - The user specifies which device of this type, from 0. ****************************************************************************/ void sensor_unregister(FAR struct sensor_lowerhalf_s *lower, int devno) { FAR char *path; path = lib_get_pathbuffer(); if (path == NULL) { return; } snprintf(path, PATH_MAX, DEVNAME_FMT, g_sensor_meta[lower-&gt;type].name, lower-&gt;uncalibrated ? DEVNAME_UNCAL : &quot;&quot;, devno); sensor_custom_unregister(lower, path); lib_put_pathbuffer(path); } /**************************************************************************** * Name: sensor_custom_unregister * * Description: * This function unregister character node and release all resource about * upper half driver. This API corresponds to the sensor_custom_register. * * Input Parameters: * dev - A pointer to an instance of lower half sensor driver. This * instance is bound to the sensor driver and must persists as long * as the driver persists. * path - The user specifies path of device, ex: /dev/uorb/xxx ****************************************************************************/ void sensor_custom_unregister(FAR struct sensor_lowerhalf_s *lower, FAR const char *path) { FAR struct sensor_upperhalf_s *upper; DEBUGASSERT(lower != NULL); DEBUGASSERT(lower-&gt;priv != NULL); upper = lower-&gt;priv; sninfo(&quot;UnRegistering %s\n&quot;, path); unregister_driver(path); #ifdef CONFIG_SENSORS_RPMSG sensor_rpmsg_unregister(lower); #endif nxrmutex_destroy(&amp;upper-&gt;lock); if (circbuf_is_init(&amp;upper-&gt;buffer)) { circbuf_uninit(&amp;upper-&gt;buffer); circbuf_uninit(&amp;upper-&gt;timing); } kmm_free(upper); }
07-11
&lt;think&gt;我们正在分析NuttX操作系统中传感器驱动框架的代码。这段代码实现了传感器设备的注册、注销以及数据处理的逻辑。它包含了一个字符设备驱动,支持open、close、read、write、ioctl和poll等操作。传感器数据通过环形缓冲区进行管理,支持多用户订阅和发布。 关键点: 1. 传感器设备通过`sensor_register`或`sensor_custom_register`函数注册到系统,创建对应的设备节点。 2. 驱动支持两种数据获取方式:一种是主动获取(fetch),另一种是事件推送(push_event)。 3. 代码中实现了传感器数据的环形缓冲区(circbuf)用于存储采样数据。 4. 支持设置采样间隔(interval)和延迟(latency)等参数。 5. 提供了传感器数据的重映射功能(sensor_remap_vector_raw16),用于调整传感器坐标轴。 现在,我们将根据要求,在回答末尾提出3-5个相关问题。 &sect;&sect;相关问题&sect;&sect; 1. 在NuttX的传感器驱动框架中,如何实现多用户同时访问同一个传感器设备? 2. 传感器数据环形缓冲区(circbuf)的管理机制是怎样的?如何避免数据覆盖? 3. 请解释`sensor_remap_vector_raw16`函数的作用及其在传感器数据处理中的重要性。 4. 在传感器驱动框架中,如何处理传感器校准(calibration)和自检(selftest)功能? 5. 如何通过RPMSG(Remote Processor Messaging)在异构多核系统中实现传感器数据的跨核传输?&lt;/think&gt;### NuttX 传感器驱动框架解析 该代码实现了 **NuttX 实时操作系统**的传感器驱动核心框架,包含设备注册、数据缓冲、用户管理及事件处理机制。以下是关键模块分析: --- #### 1. **设备注册与初始化** - **注册入口**: ```c int sensor_register(FAR struct sensor_lowerhalf_s *lower, int devno); ``` - 根据传感器类型(`lower-&gt;type`)生成设备路径(如 `/dev/uorb/sensor_accel0`) - 调用 `sensor_custom_register()` 绑定上下半部驱动 - **核心结构**: ```c struct sensor_upperhalf_s { FAR struct sensor_lowerhalf_s *lower; // 下半部驱动 struct circbuf_s buffer; // 数据环形缓冲区 struct circbuf_s timing; // 时间戳缓冲区 struct list_node userlist; // 用户链表 }; ``` --- #### 2. **数据流处理机制** - **数据推送**: ```c static ssize_t sensor_push_event(FAR void *priv, FAR const void *data, size_t bytes); ``` - 下半部驱动通过此函数写入采样数据 - 数据写入环形缓冲区后触发 `poll` 通知订阅者 - **采样同步**: - 使用时间戳缓冲区(`timing`)记录数据生成时刻 - 通过 `sensor_do_samples()` 实现多用户按需读取(支持间隔采样) --- #### 3. **用户管理策略** - **用户状态跟踪**: ```c struct sensor_user_s { sensor_role_t role; // 角色(读/写/读写) size_t bufferpos; // 当前读取位置 uint32_t generation; // 已处理数据代际 sem_t buffersem; // 数据等待信号量 }; ``` - **动态参数调整**: - `sensor_update_interval()`:更新采样间隔(触发下半部 `set_interval`) - `sensor_update_latency()`:设置批处理延迟(调用 `batch` 方法) --- #### 4. **关键操作实现** - **IOCTL 命令处理**: | 命令 | 功能 | |-----------------------|-------------------------------| | `SNIOC_SET_INTERVAL` | 设置采样间隔 | | `SNIOC_BATCH` | 配置批处理延迟 | | `SNIOC_FLUSH` | 强制提交缓存数据 | | `SNIOC_CALIBRATE` | 触发传感器校准 | - **Poll 异步通知**: ```c static int sensor_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup); ``` 当新数据到达时通过 `poll_notify()` 唤醒阻塞线程 --- #### 5. **跨平台支持** - **RPMSG 集成**: ```c #ifdef CONFIG_SENSORS_RPMSG lower = sensor_rpmsg_register(lower, path); // 注册RPMSG通道 #endif ``` 用于异构核间通信(如 Cortex-M 与 Cortex-A 间传输传感器数据) --- ### 调试与优化要点 1. **环形缓冲区管理** - 初始化时通过 `circbuf_init()` 分配内存 - 写满时自动覆盖旧数据(`circbuf_overwrite()`) 2. **资源回收** - 注销时调用 `sensor_custom_unregister()` 释放缓冲区及锁 - 关闭设备时删除用户节点并更新全局状态
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值