我理解锁,互斥和其他同步结构的概念,但它们是如何实现的?它们是由OS提供的,还是这些结构依赖于CPU MMU的特殊CPU指令?
以前我写过一些非常简单的多线程代码,而且我一直都知道在任何时候都可以在我正在做的事情中间进行上下文切换,所以我总是通过以下方式保护访问共享变量一个CCriticalSection类,它进入构造的关键部分并使其破坏.我知道这是相当激进的,我进入和离开关键部分非常频繁,有时非常惊人(例如,当我可以将CCriticalSection置于更严格的代码块中时,在函数的开头)但我的代码没有崩溃并且运行得足够快.
在工作中,我的多线程代码需要更紧密,只需要在最低级别锁定/同步.
在工作中我试图调试一些多线程代码,我遇到了这个:
EnterCriticalSection(&m_Crit4);
m_bSomeVariable = true;
LeaveCriticalSection(&m_Crit4);
Run Code Online (Sandbox Code Playgroud)
现在,m_bSomeVariable是Win32 BOOL(非易失性),据我所知,它被定义为一个int,并且在x86上读取和写入这些值是一条指令,并且因为上下文切换发生在指令边界上,所以没有必要用于将此操作与关键部分同步.
我在网上做了一些更多的研究,看看这个操作是否不需要同步,我想出了两个场景:
我相信使用"volatile"关键字可以解决数字1.在VS2005及更高版本中,C++编译器使用内存屏障围绕对此变量的访问,确保在使用变量之前始终将变量完全写入/读取到主系统内存.
2号我无法验证,我不知道为什么字节对齐会产生影响.我不知道x86指令集,但是mov需要给出一个4字节对齐的地址吗?如果不是,您需要使用指令组合吗?这会引入问题.
所以...
问题1:使用"volatile"关键字(隐含使用内存屏障并暗示编译器不优化此代码)可以避免程序员在读取/读取x86/x64变量之间同步4字节/ 8字节的需要写操作?
问题2:是否明确要求变量为4字节/ 8字节对齐?
我做了一些深入研究我们的代码和类中定义的变量:
class CExample
{
private:
CRITICAL_SECTION m_Crit1; // Protects variable a
CRITICAL_SECTION m_Crit2; // Protects variable b
CRITICAL_SECTION m_Crit3; // Protects variable c
CRITICAL_SECTION m_Crit4; // Protects variable d
// ...
};
Run Code Online (Sandbox Code Playgroud)
现在,对我来说这似乎过分了.我认为关键部分在一个进程之间同步线程,所以如果你有一个,你可以输入它,并且该进程中没有其他线程可以执行.对于要保护的每个变量,不需要关键部分,如果您处于关键部分,那么没有其他任何内容可以打断您.
我认为唯一可以从关键部分外部更改变量的是,如果进程与另一个进程共享一个内存页面(你可以这样做吗?),另一个进程开始更改值.互斥体在这里也有帮助,命名互斥体是跨进程共享的,还是只有同名的进程共享?
问题3:我对关键部分的分析是否正确,是否应该重写此代码以使用互斥锁?我看过其他同步对象(信号量和自旋锁),它们更适合这里吗?
问题4:关键部分/互斥体/信号量/自旋锁哪里最适合?也就是说,它们应该应用于哪个同步问题.选择一个而不是另一个会有很大的性能损失吗?
虽然我们正在研究它,但我读到自旋锁不应该用在单核多线程环境中,只能用于多核多线程环境.所以,问题5:这是错的,或者如果不是,为什么是对的?
在此先感谢任何回复:)
我正在尝试使用互斥方法只允许我的应用程序的一个实例运行.也就是说 - 我只想为一台机器上的所有用户提供最多一个实例.我已经阅读了关于这个问题的各种其他线程,解决方案看起来很简单,但在测试中我不能让我的第二个实例不能运行.这是我的代码......
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
// check that there is only one instance of the control panel running...
bool createdNew = true;
using (Mutex instanceMutex = new Mutex(true, @"Global\ControlPanel", out createdNew))
{
if (!createdNew)
{
Application.Current.Shutdown();
return;
}
}
base.OnStartup(e);
}
}
Run Code Online (Sandbox Code Playgroud) 我需要停止一个线程,直到另一个线程设置一个布尔值,我不想在它们之间共享一个事件.
我目前所拥有的是使用Sleep的以下代码(这是我想要更改的代码):
while (!_engine.IsReadyToStop())
{
System.Threading.Thread.Sleep(Properties.Settings.Default.IntervalForCheckingEngine);
}
Run Code Online (Sandbox Code Playgroud)
有任何想法吗?
编辑澄清事:
我不拥有一个名为_engine的对象.我无法修改它,这就是为什么我不想在它们之间共享事件.我需要等到该类的方法返回true.
我正在调用异步实现的方法:
let mut safebrowsing: MutexGuard<Safebrowsing> = self.safebrowsing.lock().unwrap();
safebrowsing.is_safe(input: &message.content).await;
Run Code Online (Sandbox Code Playgroud)
is_safe -方法:
pub async fn is_safe(&mut self, input: &str) {
let links = self.finder.links(input);
for link in links {
match reqwest::get("url").await {
Ok(response) => {
println!(
"{}",
response.text().await.expect("response has no content")
);
}
Err(_) => {
println!("Unable to get safebrowsing-response")
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是,通过异步调用is_safe -方法,编译器告诉我线程无法安全发送。该错误是关于:
future cannot be sent between threads safely
within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, Safebrowsing>`
required for the cast …Run Code Online (Sandbox Code Playgroud) 我正在重新编写可以多次启动的Java可执行文件,我希望一次一个进程.在C#中,我会使用命名/系统Mutex执行此操作,但这在Java中似乎不可能.我该如何实现此功能?
我一直在阅读多线程和共享资源访问,其中一个(对我而言)新概念是互斥锁.我似乎无法找到的是发现"临界区"被锁定的线程实际发生的情况.它说在许多地方线程被"阻止",但这意味着什么?是否暂停,锁定解除后会恢复吗?或者它会在"运行循环"的下一次迭代中再次尝试?
我问的原因是因为我想要系统提供的事件(鼠标,键盘等),它们(显然)在主线程上传递,在我的辅助线程的运行循环中的一个非常特定的部分处理.因此无论发生什么事件,我都会在自己的数据结构中排队.显然,数据结构需要一个互斥锁,因为它被两个线程修改.缺少的难题是:当事件在主线程上的函数中传递时会发生什么,我想将其排队,但是队列被锁定了?主线程是否会被暂停,还是会跳过锁定的部分并超出范围(丢失事件)?
我正在尝试学习pthread_cond_wait的基础知识.在所有用法中,我也看到了
if(cond is false)
pthread_cond_wait
Run Code Online (Sandbox Code Playgroud)
要么
while(cond is false)
pthread_cond_wait
Run Code Online (Sandbox Code Playgroud)
我的问题是,我们只想cond_wait因为条件是假的.那么为什么我要明确地设置一个if/while循环的痛苦.我可以理解,在没有任何if/while检查之前cond_wait我们会直接命中它并且它根本不会返回.条件检查仅用于解决此目的还是具有其他意义.如果它用于解决不必要的条件等待,那么进行条件检查并避免使用cond_wait类似于轮询?我正在使用像这样的cond_wait.
void* proc_add(void *name){
struct vars *my_data = (struct vars*)name;
printf("In thread Addition and my id = %d\n",pthread_self());
while(1){
pthread_mutex_lock(&mutexattr);
while(!my_data->ipt){ // If no input get in
pthread_cond_wait(&mutexaddr_add,&mutexattr); // Wait till signalled
my_data->opt = my_data->a + my_data->b;
my_data->ipt=1;
pthread_cond_signal(&mutexaddr_opt);
}
pthread_mutex_unlock(&mutexattr);
if(my_data->end)
pthread_exit((void *)0);
}
}
Run Code Online (Sandbox Code Playgroud)
逻辑是,我要求输入线程在输入可用时处理数据,并通知输出线程打印它.
我正在阅读drdobbs.com上的Boost Mutex教程,并发现了这段代码:
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>
boost::mutex io_mutex;
void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}
int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在我明白Mutex的意思是防止两个线程同时访问同一个资源,但我没有看到io_mutex和std :: cout之间的相关性.这个代码是否只是锁定范围内的所有内容,直到范围完成为止?
我需要一些帮助来了解如何在C中使用条件变量来解决练习.这是一个小例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#define OKTOWRITE "/oktowrite"
#define MESSAGE "/message"
#define MUTEX "/lock"
int main(int argc, char** argv)
{
pthread_cond_t* condition;
pthread_mutex_t *mutex;
char* message;
int des_cond, des_msg, des_mutex;
int mode = S_IRWXU | S_IRWXG;
des_mutex = shm_open(MUTEX, O_CREAT | O_RDWR | O_TRUNC, mode);
if (des_mutex < 0)
{
perror("failure on shm_open on des_mutex");
exit(1);
}
if (ftruncate(des_mutex, sizeof(pthread_mutex_t)) == -1)
{
perror("Error …Run Code Online (Sandbox Code Playgroud)