什么功能对应于“同步”?在Java中?

发布于 2024-10-27 03:51:28 字数 65 浏览 1 评论 0 原文

Java中的synchronized可以保证访问共享对象时的线程安全。 那么 C++ 呢?

synchronized in Java can guarantee thread-safety when accessing a shared object.
What about C++?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

一笔一画续写前缘 2024-11-03 03:51:29

在 C++ 中,我实现了一个宏,让您只需执行以下操作即可同步对函数或方法的访问:

// Define a function we want to synchronize.
void synchronizedFunction()
{
    // Synchronize this function.
    synchronized;

    // We are now synchronized.
}

宏的定义方式如下:

// Under the hood, we use a mutex to synchronize.
#include <mutex>

// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))

这对我来说适用于所有三种流行的编译器 { Windows、Clang、GCC } 。该宏为该函数创建一个唯一的静态互斥变量,并立即将其锁定在该函数的范围内。它也可以在任何范围内使用,而不仅仅是函数范围。

您可以尝试这个测试程序来证明它是有效的:

// Under the hood, we use a mutex to synchronize.
#include <mutex>

// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))

// For our test program below.
#include <iostream>
#include <thread>

// Define a function we want to synchronize.
void synchronizedFunction()
{
    // Synchronize this function.
    synchronized;

    // Print something, then sleep for 1 second, then print something else.
    // If we're synchronized, these two messages will appear back-to-back.
    // If we're not synchronized, these messages display in an uncontrolled fashion.
    std::cout << "Thread " << std::this_thread::get_id() << " is entering." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread " << std::this_thread::get_id() << " is exiting." << std::endl;
}

// A simple test program that will access our synchronized function from 2 asynchronous threads.
int main()
{
    // Construct a new thread and have it call our synchronized function.
    std::thread newThread(synchronizedFunction);

    // In our main thread, also call our synchronized function.
    synchronizedFunction();
    
    // Join both threads before exiting.
    newThread.join();
    
    // Exit.
    return 0;
}

当您运行这个程序时,您会得到以下输出——证明每个访问线程对函数的访问都是序列化的。您会注意到从进入函数到退出函数(两次)都有一秒的延迟。因为该函数现在已序列化,所以测试程序大约需要 2 秒才能完成该函数:

Thread 140737353824064 is entering.
Thread 140737353824064 is exiting.
Thread 140737257031424 is entering.
Thread 140737257031424 is exiting.

如果注释掉“synchronized;”语句,那么您将看到两个线程几乎同时进入该函数,产生类似于以下输出的内容,或者您​​可能会看到文本踩在其自身之上。因为我们不再同步,所以测试程序将花费大约 1 秒而不是 2 秒来完成:

Thread 140737257031424 is entering.
Thread 140737353824064 is entering.
Thread 140737257031424 is exiting.
Thread 140737353824064 is exiting.

In C++, I've implemented a macro that lets you simply do the following in order to synchronize access to a function or method:

// Define a function we want to synchronize.
void synchronizedFunction()
{
    // Synchronize this function.
    synchronized;

    // We are now synchronized.
}

Here's how the macro is defined:

// Under the hood, we use a mutex to synchronize.
#include <mutex>

// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))

This works for me with all three popular compilers { Windows, Clang, GCC }. This macro creates a unique static mutex variable for the function, and immediately locks it within the scope of that function. It could also be used within any scope, not just a function scope.

You can try this test program to prove that it works:

// Under the hood, we use a mutex to synchronize.
#include <mutex>

// Create a synchronized keyword.
#define CONCAT_INNER(a, b) a##b
#define CONCAT(a, b) CONCAT_INNER(a, b)
#define UNIQUE_NAME(base) CONCAT(base, __LINE__)
#define synchronized static std::mutex UNIQUE_NAME(syncMutex); std::unique_lock<std::mutex> syncLock(UNIQUE_NAME(syncMutex))

// For our test program below.
#include <iostream>
#include <thread>

// Define a function we want to synchronize.
void synchronizedFunction()
{
    // Synchronize this function.
    synchronized;

    // Print something, then sleep for 1 second, then print something else.
    // If we're synchronized, these two messages will appear back-to-back.
    // If we're not synchronized, these messages display in an uncontrolled fashion.
    std::cout << "Thread " << std::this_thread::get_id() << " is entering." << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Thread " << std::this_thread::get_id() << " is exiting." << std::endl;
}

// A simple test program that will access our synchronized function from 2 asynchronous threads.
int main()
{
    // Construct a new thread and have it call our synchronized function.
    std::thread newThread(synchronizedFunction);

    // In our main thread, also call our synchronized function.
    synchronizedFunction();
    
    // Join both threads before exiting.
    newThread.join();
    
    // Exit.
    return 0;
}

When you run this program, you get the following output -- demonstrating that access to the function is serialized for each accessing thread. You will notice the one-second delay from when the function is entered and when the function has exited (both times). Because the function is now serialized, the test program will take approximately 2 seconds for this function to complete:

Thread 140737353824064 is entering.
Thread 140737353824064 is exiting.
Thread 140737257031424 is entering.
Thread 140737257031424 is exiting.

If you comment out the "synchronized;" statement, then you'll see that both threads enter the function almost simultaneously, producing something similar to the following output, or you may see text that stomps on top of itself. Because we are no longer synchronized, the test program will take approximately 1 second to complete instead of 2 seconds:

Thread 140737257031424 is entering.
Thread 140737353824064 is entering.
Thread 140737257031424 is exiting.
Thread 140737353824064 is exiting.
梦旅人picnic 2024-11-03 03:51:28

在 C++ 中使用以下内容:

#include <mutex>

std::mutex _mutex;

void f()
{
     std::unique_lock<std::mutex> lock(_mutex);
     // access your resource here.
}

Use the following in C++:

#include <mutex>

std::mutex _mutex;

void f()
{
     std::unique_lock<std::mutex> lock(_mutex);
     // access your resource here.
}
最冷一天 2024-11-03 03:51:28

尽管这个问题已经得到解答,但通过 这篇文章我仅使用标准库 (C++11) 对象制作了我的 synchronized 关键字版本:

#include <mutex>
#define synchronized(m) \
    for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())

您可以像这样测试它:

#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>
#include <vector>

#define synchronized(m) \
    for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())

class Test {
    std::recursive_mutex m_mutex;
public:
    void sayHello(int n) {
        synchronized(m_mutex) {
            std::cout << "Hello! My number is: ";
            std::cout << std::setw(2) << n << std::endl;
        }
    }    
};

int main() {
    Test test;
    std::vector<std::thread> threads;
    std::cout << "Test started..." << std::endl;

    for(int i = 0; i < 10; ++i)
        threads.push_back(std::thread([i, &test]() {
            for(int j = 0; j < 10; ++j) {
                test.sayHello((i * 10) + j);
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }));    
    for(auto& t : threads) t.join(); 

    std::cout << "Test finished!" << std::endl;
    return 0;
}

这只是一个近似值Java 的 synchonized 关键字,但它有效。如果没有它,上一个示例的 sayHello 方法可以按照 接受的答案 来实现:

void sayHello(unsigned int n) {
    std::unique_lock<std::recursive_mutex> lk(m_mutex);

    std::cout << "Hello! My number is: ";
    std::cout << std::setw(2) << n << std::endl;
}

Despite this question has been already answered, by the idea of this article I made my version of synchronized keyword using just standard library (C++11) objects:

#include <mutex>
#define synchronized(m) \
    for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())

You can test it like:

#include <iostream>
#include <iomanip>
#include <mutex>
#include <thread>
#include <vector>

#define synchronized(m) \
    for(std::unique_lock<std::recursive_mutex> lk(m); lk; lk.unlock())

class Test {
    std::recursive_mutex m_mutex;
public:
    void sayHello(int n) {
        synchronized(m_mutex) {
            std::cout << "Hello! My number is: ";
            std::cout << std::setw(2) << n << std::endl;
        }
    }    
};

int main() {
    Test test;
    std::vector<std::thread> threads;
    std::cout << "Test started..." << std::endl;

    for(int i = 0; i < 10; ++i)
        threads.push_back(std::thread([i, &test]() {
            for(int j = 0; j < 10; ++j) {
                test.sayHello((i * 10) + j);
                std::this_thread::sleep_for(std::chrono::milliseconds(100));
            }
        }));    
    for(auto& t : threads) t.join(); 

    std::cout << "Test finished!" << std::endl;
    return 0;
}

This is just an approximation of synchonized keyword of Java but it works. Without it the sayHello method of the previous example can be implemented as the accepted answer says:

void sayHello(unsigned int n) {
    std::unique_lock<std::recursive_mutex> lk(m_mutex);

    std::cout << "Hello! My number is: ";
    std::cout << std::setw(2) << n << std::endl;
}
喵星人汪星人 2024-11-03 03:51:28

C++03 中没有与 Java 中的 synchronized 等效的关键字。但是可以使用Mutex来保证线程的安全。

There is no keyword in C++03 equivalent to synchronized in Java . But you can use Mutex to guarantee safety of thread.

昵称有卵用 2024-11-03 03:51:28

C++ 还没有内置线程或同步,您必须为此使用库。 Boost.Thread 是一个良好的可移植库,旨在与 C++0x 中建议的线程设施兼容

C++ does not have built-in threading or synchronization (yet), you have to use libraries for that. Boost.Thread is a good portable library that is designed to be compatible with the proposed threading facilities in C++0x.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文