我正在做一个C应用程序,它读取并解析来自一组传感器的数据,并根据传感器的读数打开或关闭执行器。
对于我的应用程序,我将使用两个线程,一个用于读取和解析来自传感器的数据,另一个用于执行器上的数据。显然,我们可能会遇到一个线程从某个变量读取数据而另一个线程试图在其上写入数据的问题。这是一个示例代码。
#include <pthread.h>
int sensor_values;
void* reads_from_sensor(){
//writes on sensor_values, while(1) loop
}
void* turns_on_or_off(){
//reads from sensor_values, while(1) loop
}
int main(){
pthread_t threads[2];
pthread_create(&threads[1],NULL,reads_from_sensor,NULL);
pthread_create(&threads[2],NULL,turns_on_or_off,NULL);
//code continues after
}
我的问题是如何解决这个问题,某个线程在某个全局变量上写入,同时其他线程试图从中读取。提前谢谢。
答案 0 :(得分:0)
OP在评论中写道
该项目仍处于alpha阶段。我会确保一旦完成就优化它。 @Pablo,共享变量是
sensor_values
。reads_from_sensors
写在上面,turns_on_or_off
从中读取。...
sensor_value
将是float
,因为它存储由特定传感器测量的值。该值可以是电压,温度或湿度
在这种情况下,我会使用pthread_cond_wait
和pthread_cond_signal
来使用条件变量
understanding of pthread_cond_wait()
and pthread_cond_signal()
。使用这些函数,您可以同步线程
彼此。
这个想法是两个线程都获得指向mutx的指针,即条件变量 和共享资源,无论您是将它们声明为全局还是将它们作为全局传递 线程参数,不改变主意。在下面的代码中,我正在通过所有 这些作为线程参数,因为我不喜欢全局变量。
读取线程将锁定互斥锁,并在读取新值时使用
传感器,它将新值写入共享资源。然后它打电话
pthread_cond_signal
向转动线程发送一个新值的信号
到了,它可以从中读取。
转弯线程还会锁定互斥锁并执行pthread_cond_wait
等待信号。锁定必须以这种方式完成,因为
pthread_cond_wait
将释放锁并使线程阻塞直到
信号发送:
man pthread_cond_wait
<强>描述强>
pthread_cond_timedwait()
和pthread_cond_wait()
函数应阻止条件变量。 申请应确保 调用这些函数时mutex
被调用线程锁定;否则,是一个错误(对于PTHREAD_MUTEX_ERRORCHECK
而且是强大的 互斥体)或未定义的行为(对于其他互斥体)结果。这些函数以原子方式释放互斥锁并导致调用线程阻塞条件变量cond;这里原子意味着 关于另一个线程访问互斥锁然后条件变量的原子方式。也就是说,如果另一个线程是 能够在即将发布的线程释放后获取互斥锁,然后调用
pthread_cond_broadcast()
或 该线程中的pthread_cond_signal()
应该表现得就像在约会阻塞线程被阻止后发布一样。
示例:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
struct thdata {
pthread_mutex_t *mutex;
pthread_cond_t *cond;
int *run;
float *sensor_value; // the shared resource
};
void *reads_from_sensors(void *tdata)
{
struct thdata *data = tdata;
int i = 0;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
// read from sensor
*data->sensor_value = (rand() % 2000 - 1000) / 10.0;
// just for testing, send a singnal only every
// 3 reads
if((++i % 3) == 0)
{
printf("read: value == %f, sending signal\n", *data->sensor_value);
pthread_cond_signal(data->cond);
}
pthread_mutex_unlock(data->mutex);
sleep(1);
}
// sending signal so that other thread can
// exit
pthread_mutex_lock(data->mutex);
pthread_cond_signal(data->cond);
pthread_mutex_unlock(data->mutex);
puts("read: bye");
pthread_exit(NULL);
}
void *turns_on_or_off (void *tdata)
{
struct thdata *data = tdata;
while(*data->run)
{
pthread_mutex_lock(data->mutex);
pthread_cond_wait(data->cond, data->mutex);
printf("turns: value read: %f\n\n", *data->sensor_value);
pthread_mutex_unlock(data->mutex);
usleep(1000);
}
puts("turns: bye");
pthread_exit(NULL);
}
int main(void)
{
srand(time(NULL));
struct thdata thd[2];
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
// controlling vars
int run_rfs = 1;
int run_tof = 1;
float sensor_value;
thd[0].run = &run_rfs;
thd[1].run = &run_tof;
thd[0].mutex = &mutex;
thd[1].mutex = &mutex;
thd[0].cond = &cond;
thd[1].cond = &cond;
thd[0].sensor_value = &sensor_value;
thd[1].sensor_value = &sensor_value;
pthread_t th[2];
printf("Press ENTER to exit...\n");
pthread_create(th, NULL, reads_from_sensors, thd);
pthread_create(th + 1, NULL, turns_on_or_off, thd + 1);
getchar();
puts("Stopping threads...");
run_rfs = 0;
run_tof = 0;
pthread_join(th[0], NULL);
pthread_join(th[1], NULL);
return 0;
}
输出:
$ ./a
Press ENTER to exit...
read: value == -99.500000, sending signal
turns: value read: -99.500000
read: value == -25.200001, sending signal
turns: value read: -25.200001
read: value == 53.799999, sending signal
turns: value read: 53.799999
read: value == 20.400000, sending signal
turns: value read: 20.400000
Stopping threads...
read: bye
turns: value read: 20.400000
turns: bye
请注意,在示例中,我每隔3秒发送一次信号(并做很长时间)
sleep(1)
)用于测试目的,否则终端会立即溢出
你会很难读出输出。
另请参阅:{{3}}
答案 1 :(得分:0)
你的问题太笼统了。有多种不同的多线程同步方法互斥,读写器锁,条件变量等。
最简单也是最简单的是互斥(互斥)。它们是pthread_mutex_t
类型变量。你首先需要初始化它们;你可以用两种方式做到这一点:
PTHREAD_MUTEX_INITIALIZER
pthread_mutex_init
然后在阅读或编写共享变量之前,您调用函数int pthread_mutex_lock(pthread_mutex_t *mutex);
,在退出关键部分后,您必须通过调用int pthread_mutex_unlock(pthread_mutex_t *mutex);
来释放关键部分。
如果资源繁忙,锁将阻止代码的执行,直到它被释放。如果您想避免这种情况,请查看int pthread_mutex_trylock(pthread_mutex_t *mutex);
。
如果您的程序读取的次数多于同一共享变量的读取次数,请查看Reader-Writer锁定。