I have searched the web for a while now trying to resolve this issue, but have had no success.
In my application, I have a large set of messages that I am attempting to encrypt using a basic commutative encryption scheme. Since the sets are large numbers of BigIntegers, I am attempting to multithread the encryptions to increase performance.
Basically, I take the large set of messages and split it up into subsets that are passed to an encryption thread to do a subset of the encryptions. Then I attempt to extract each subset and aggregate them into the original large set after the threads have all done their parts.
When I iterate over the threads and pull out each of their encryptions, the error is occurring when I attempt to actually addAll of the encryptions to the list of all encryptions and the error it throws is the java.util.ConcurrentModificationException error.
I have attempted to use synchronization, but it isn't helping.
Here is the function call:
protected Set<BigInteger> multiEncrypt(BigInteger key, HashSet<BigInteger> messageSet) {
ArrayList<BigInteger> messages = new ArrayList<BigInteger>(messageSet);
Set<BigInteger> encryptions = Collections.synchronizedSet(new HashSet<BigInteger>());
int cores = Runtime.getRuntime().availableProcessors();
int numMessages = messages.size();
int stride = numMessages/cores;
//create all the threads and run them
ArrayList<EncryptThread> threads = new ArrayList<EncryptThread>();
for (int thread = 0; thread < cores; thread++) {
int start = thread*stride;
//don't want to go over the end
int stop = ((thread+1)*stride >= messages.size()) ? messages.size()-1 : (thread+1)*stride;
List<BigInteger> subList = messages.subList(start, stop);
EncryptThread t = new EncryptThread(encryptionScheme.getPrime(), key, subList);
t.start();
threads.add(t);
}
//pull out the encryptions
synchronized(encryptions){
for (int i=0; i < threads.size()-1; i++) {
EncryptThread thread = threads.get(i);
ArrayList<BigInteger> these = thread.getEncryptions();
encryptions.addAll(these); //<-- Erroring Here
thread.finish();
}
}
And here are the relevant parts of the EncryptThread class I wrote to do the encryptions:
/**
* Constructor
*/
public EncryptThread(BigInteger prime, BigInteger key, List<BigInteger> messages) {
//need a new encryption scheme object for each thread
encryptionScheme = new EncryptionScheme(prime);
encryptions = new ArrayList<BigInteger>();
this.key = key;
this.messages = messages;
wait = true;
}
#Override
public void run() {
encryptMessages(key, messages);
while(wait);
}
/**
* Used to encrypt a set of messages
* #param key
* #param messages
* #return
*/
public void encryptMessages(BigInteger key, List<BigInteger> messages) {
System.out.println("Encrypting stuff");
for (BigInteger m : messages) {
BigInteger em = encryptionScheme.encrypt(key, m);
encryptions.add(m);
}
}
public ArrayList<BigInteger> getEncryptions() {
return encryptions;
}
//call this after encryptions have been pulled to let the thread finish
public void finish() {
wait = false;
}
}
I am not new to Java, but I am new to multi threading in java and so I would appreciate any and all advice. Thanks in advance!
EDIT: As per the suggestions, I added a simple locking mechanism to the EncryptThread class, which makes the thread wait to return the encryptions until they are all done and it works now.
public void encryptMessages(BigInteger key, List<BigInteger> messages) {
System.out.println("Encrypting stuff");
this.lock = true;
for (BigInteger m : messages) {
BigInteger em = encryptionScheme.encrypt(key, m);
//deals with when we have to mark chaff at S2
if (shift) {
em.shiftLeft(1);
if(shiftVal != 0) em.add(BigInteger.ONE);
}
encryptions.add(m);
}
this.lock = false;
}
public ArrayList<BigInteger> getEncryptions() {
while(lock);
return encryptions;
}
EDIT #2 So I ended up using a solution which was suggested to me by someone from my lab. I got rid of the lock and wait booleans, and the finish() function in the EncryptThread class, and instead added a simple thread.join() loop between the start and getEncryption loops:
//create all the threads
ArrayList<EncryptThread> threads = new ArrayList<EncryptThread>();
for (int thread = 0; thread < cores; thread++) {
int start = thread*stride;
//don't want to go over the end
int stop = ((thread+1)*stride >= messages.size()) ? messages.size()-1 : (thread+1)*stride;
List<BigInteger> subList = messages.subList(start, stop);
EncryptThread t = new EncryptThread(encryptionScheme.getPrime(), key, subList, shiftVal);
t.start();
threads.add(t);
}
//wait for them to finish
for( EncryptThread thread: threads) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//pull out the encryptions
for (int i=0; i < threads.size()-1; i++) {
EncryptThread thread = threads.get(i);
encryptions.addAll(thread.getEncryptions());
}
I think my main confusion was that I thought a thread class couldn't have its methods called on it after it had finished running. But the above works fine.
ConcurrentModificationException happens when you modify a Collection while you're iterating over it. It has very little to do with multi threading, since you can easily create a single threaded example:
ArrayList<String> myStrings = new ArrayList<>();
myStrings.add("foo");
myStrings.add("bar");
for(String s : myStrings) {
myStrings.add("Hello ConcurrentModificationException!");
If you look at the documentation on List's addAll, it says the following:
Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator (optional operation). The behavior of this operation is undefined if the specified collection is modified while the operation is in progress. (Note that this will occur if the specified collection is this list, and it's nonempty.)
You can see your List being modified while addAll is using it's iterator in your encryptMessages method that one of your threads you spawned is currently executing.
for (BigInteger m : messages) {
BigInteger em = encryptionScheme.encrypt(key, m);
encryptions.add(m); // <-- here
}
I didn't look through all of your code fully, but some of the stuff here is not thread safe. You might do well using a CopyOnWriteArrayList instead of a regular ArrayList to avoid the ConcurrentModificationException, that's if, you are okay with not having everything added to the list in the addAll call, if you aren't, you also then need to be waiting for the threads to finish. You probably want to instead just use tasks with an ExecutorService. There's other improvements to make as well probably.
In additional, the goto book everyone mentions to learn how to write thread safe programs in Java is Concurrency in Practice, I'd recommend that if you are new to concurrency in Java.
you are starting your threads here.
for (int thread = 0; thread < cores; thread++) {
int start = thread*stride;
//don't want to go over the end
int stop = ((thread+1)*stride >= messages.size()) ? messages.size()-1 : (thread+1)*stride;
List<BigInteger> subList = messages.subList(start, stop);
EncryptThread t = new EncryptThread(encryptionScheme.getPrime(), key, subList);
t.start();
threads.add(t);
}
Well. Then you have to wait for all threads to get complete , before start aggregate in this block.
//pull out the encryptions
synchronized(encryptions){
for (int i=0; i < threads.size()-1; i++) {
EncryptThread thread = threads.get(i);
ArrayList<BigInteger> these = thread.getEncryptions();
encryptions.addAll(these); //<-- Erroring Here
thread.finish();
}
}
you are blocking threads which are accessing encryptions only. but the thread you have created is not accessing the set . mean time it will keep on add to its own array List these . So when you call encryptions.addAll(these); these is accessed by two threads ( thread owning encryptions and the thread owning these
And the other answers provided detail about why Concurrent exception in addAll.
You have to wait until all the threads get complete thier work.
You can do this using ExecutorService
Change your starting thread as
ExecutorService es = Executors.newFixedThreadPool(cores);
for(int i=0;i<5;i++)
es.execute(new Runnable() { /* your task */ }); //EncryptThread instance
es.shutdown();
boolean finshed = es.awaitTermination(1, TimeUnit.MINUTES);
Then process your adding back process.
ExecutorService es = Executors.newFixedThreadPool(cores);
for (int thread = 0; thread < cores; thread++) {
int start = thread*stride;
//don't want to go over the end
int stop = ((thread+1)*stride >= messages.size()) ? messages.size()-1 : (thread+1)*stride;
List<BigInteger> subList = messages.subList(start, stop);
EncryptThread t = new EncryptThread(encryptionScheme.getPrime(), key, subList);
es.execute(t);
threads.add(t);
}
es.shutdown();
boolean finshed = es.awaitTermination(1, TimeUnit.MINUTES);
//pull out the encryptions
synchronized(encryptions){
for (int i=0; i < threads.size()-1; i++) {
EncryptThread thread = threads.get(i);
ArrayList<BigInteger> these = thread.getEncryptions();
encryptions.addAll(these); //<-- Erroring Here
thread.finish();
}
}
Assumed, your EncryptThread is Thread right now. you might need to change to implements Runnable. and no other change in getEncryptions
Related
While writing a state-space search like algorithm, I have a working queue with node elements. I have multiple threads with access to that queue that pop an element, do some transformations and checks to it, and may add more nodes to be visited to the queue.
I want the program to stop whenever the queue is empty, and all threads have stopped working (since they could add more elements in which case we would need the other threads to help handling these new nodes).
How should I go about making that check? I was currently thinking keeping some AtomicBitSet, keeping track of which threads are working and which are not, and stop execution when the bitset is empty. I would set and unset with the following, in the run method of my handlers
while (!bitset.isAllUnset()) {
Node node = queue.poll();
if (node == null) {
bitset.unset(THREAD_INDEX);
} else {
bitset.set(THREAD_INDEX);
// HANDLE THE NODE
}
}
Is there any recommended method to go about this?
What you could do is the following approach:
Create a ThreadPool and push the initial Task to your Queue.
Keep one Thread (you main Thread) as a Monitor on the ThreadPool.
The job of this Thread is to start new Threads as long as the Queue is not empty, the Thread Pool still has capacity left and give them their Task.
A Thread that is started will do its job and writes the results back to the queue.
Afterwards it is returned to the pool and you will have to wake up your Monitor.
Your Main Thread will then try to start a new thread as long as the Thread Pool has not reached is limit and the Task Queue is not empty.
Use an ExecutorService to which you submit the Runnables that read the queue and which stop running when the queue is empty.
Then call the executor service 's awaitTermination() method which will block until all threads are finished.
Or use CompletableFuture:
CompleteableFuture.allOf(
CompleteableFuture.runAsync(
() -> while(!queue.isEmpty()) handle(queue.poll())
));
I think this is actually rather complicated. I do not know how to write a correct version using a set based approach. For example, the following approach is wrong:
public class ThreadsStopWorkingWrong {
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
ConcurrentHashMap activeThreads = new ConcurrentHashMap();
volatile int prozessedCount = 0;
volatile boolean stop = false;
#Interleave(group = ThreadsStopWorkingWrong.class, threadCount = 1)
public void readFromQueue() {
int prozessAdditionalElements = 1;
while (!stop) {
Object element = queue.poll();
if (element != null) {
activeThreads.put(Thread.currentThread(), "");
if (prozessAdditionalElements > 0) {
prozessAdditionalElements--;
queue.offer("2");
}
prozessedCount++;
} else {
activeThreads.remove(Thread.currentThread());
}
}
}
#Interleave(group = ThreadsStopWorkingWrong.class, threadCount = 1)
public void waitTillProzessed() throws InterruptedException {
while (!queue.isEmpty() && !activeThreads.isEmpty()) {
Thread.sleep(1);
}
assertEquals(2, prozessedCount);
}
#Test
public void test() throws InterruptedException {
queue.offer("1");
Thread worker = new Thread(() -> readFromQueue());
worker.start();
waitTillProzessed();
worker.join();
}
}
The problem is that when you poll the message out of the queue you have not yet added the thread to the activated set so !queue.isEmpty() && !activeThreads.isEmpty() becomes true. What works is using a message counter as in the following example:
public class ThreadsStopWorkingCorrect {
ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue();
AtomicLong messageCount = new AtomicLong();
volatile int prozessedCount = 0;
volatile boolean stop = false;
#Interleave(group = ThreadsStopWorkingCorrect.class, threadCount = 1)
public void readFromQueue() {
int prozessAdditionalElements = 1;
while (!stop) {
Object element = queue.poll();
if (element != null) {
if (prozessAdditionalElements > 0) {
prozessAdditionalElements--;
queue.offer("2");
messageCount.incrementAndGet();
}
prozessedCount++;
messageCount.decrementAndGet();
}
}
}
#Interleave(group = ThreadsStopWorkingCorrect.class, threadCount = 1)
public void waitTillProzessed() throws InterruptedException {
while (messageCount.get() > 0) {
Thread.sleep(1);
}
assertEquals(2, prozessedCount);
}
#Test
public void test() throws InterruptedException {
queue.offer("1");
messageCount.incrementAndGet();
Thread worker = new Thread(() -> readFromQueue());
worker.start();
waitTillProzessed();
worker.join();
}
}
I tested both the example with vmlens, a tool I wrote to test multithreaded software. Therefore the Interleave annotations.
In the set-based version, some thread interleavings lead to prozessedCount==0.
In the counter-based version, the prozessedCount is always 2.
There is one ArrayList with 1 million element and we are using two threads to read from this ArrayList. The first thread will read first half of the list and second thread will read the second half of list and I am using two threads to achieve this, but I don't see any difference in performance between using one thread and two threads.
I have written below program to achieve this, but I am not sure If this is the right way to implement and achieve this.
Can someone check if my code is correct or how I can fix the multithreading?
import java.util.ArrayList;
import java.util.List;
public class ThreadTask {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
List<Integer> list = new ArrayList<>();
for(int i = 0; i <=1000000; i++){
list.add(i);
}
Thread t1 = new Thread(new PrintList(list));
Thread t2 = new Thread(new PrintList(list));
t1.setName("thread1");
t2.setName("thread2");
long starttime = System.currentTimeMillis();
System.out.println(starttime);
t1.start();
t2.start();
t1.join();
t2.join();
long endtime = System.currentTimeMillis();
System.out.println(endtime);
System.out.println("Total time "+(endtime - starttime));
}
}
class PrintList implements Runnable{
private List list = new ArrayList();
public PrintList(List list){
this.list = list;
}
#Override
public void run() {
if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread1")){
for(int i = 0; i< list.size()/2;i++){
// System.out.println("Thread 1 "+list.get(i));
}
}else if(Thread.currentThread().getName() != null && Thread.currentThread().getName().equalsIgnoreCase("thread2")){
for(int i = list.size()/2; i<list.size(); i++){
//System.out.println("Thread 2 "+list.get(i));
}
}
}
}
Also, If someone can help me on how can we implement it to make it generic to use more then to thread.
System.out.println is synchronized internally (in order that you don't get mixing between the messages printed by multiple threads), so only one thread is actually printing at once.
Basically, it behaves like a single thread.
Even if in reality System.out is synchronized, still you dont want to have manually initialized threads reading from your ArrayList. Plus I doubt that your end goal is the System.out. You should use a higher abstraction. Such abstraction can easily be present either through Java8 Stream API either by ExecutorServices.
Here is one example of paralelism with Java 8 api.
Arraylist toprint;
toPrint.parallelstream().forEach(DoSometing);
This will work in parallel threads.
If you use ExecutorService You can slice your Arraylist and pass each slice to a Callable to perform the work for you in a separate thread.
class Task implements Callable {
List sublist;
public Task(List sublist) {
this.sublist = sublist;
}
public void call() {
// do something
}
}
ArrayList listToSlice;
List<List> slicedList;
ExecutorService executor = Executors.newFixedThreadPool(2);
for (List sublist:slicedList) {
Future<Integer> future = executor.submit(new Task(sublist));
......
.......s on
}
I have written a simple program, that is intended to start a few threads. The threads should then pick a integer n from an integer array, use it to wait n and return the time t the thread waited back into an array for the results.
If one thread finishes it's task, it should pick the next one, that has not yet being assigned to another thread.
Of course: The order in the arrays has to be maintained, so that integers and results match.
My code runs smoothly as far I see.
However I use one line of code block I find in particular unsatisfying and hope there is a good way to fix this without changing too much:
while(Thread.activeCount() != 1); // first evil line
I kinda abuse this line to make sure all my threads finish getting all the tasks done, before I access my array with the results. I want to do that to prevent ill values, like 0.0, Null Pointer Exception... etc. (in short anything that would make an application with an actual use crash)
Any sort of constructive help is appreciated. I am also not sure, if my code still runs smoothly for very very long arrays of tasks for the threads, for example the results no longer match the order of the integer.
Any constructive help is appreciated.
First class:
public class ThreadArrayWriterTest {
int[] repitions;
int len = 0;
double[] timeConsumed;
public boolean finished() {
synchronized (repitions) {
return len <= 0;
}
}
public ThreadArrayWriterTest(int[] repitions) {
this.repitions = repitions;
this.len = repitions.length;
timeConsumed = new double[this.len];
}
public double[] returnTimes(int[] repititions, int numOfThreads, TimeConsumer timeConsumer) {
for (int i = 0; i < numOfThreads; i++) {
new Thread() {
public void run() {
while (!finished()) {
len--;
timeConsumed[len] = timeConsumer.returnTimeConsumed(repititions[len]);
}
}
}.start();
}
while (Thread.activeCount() != 1) // first evil line
;
return timeConsumed;
}
public static void main(String[] args) {
long begin = System.currentTimeMillis();
int[] repitions = { 3, 1, 3, 1, 2, 1, 3, 3, 3 };
int numberOfThreads = 10;
ThreadArrayWriterTest t = new ThreadArrayWriterTest(repitions);
double[] times = t.returnTimes(repitions, numberOfThreads, new TimeConsumer());
for (double d : times) {
System.out.println(d);
}
long end = System.currentTimeMillis();
System.out.println("Total time of execution: " + (end - begin));
}
}
Second class:
public class TimeConsumer {
double returnTimeConsumed(int repitions) {
long before = System.currentTimeMillis();
for (int i = 0; i < repitions; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
long after = System.currentTimeMillis();
double ret = after - before;
System.out.println("It takes: " + ret + "ms" + " for " + repitions + " runs through the for-loop");
return ret;
}
}
The easiest way to wait for all threads to complete is to keep a Collection of them and then call Thread.join() on each one in turn.
In addition to .join() you can use ExecutorService to manage pools of threads,
An Executor that provides methods to manage termination and methods
that can produce a Future for tracking progress of one or more
asynchronous tasks.
An ExecutorService can be shut down, which will cause it to reject new
tasks. Two different methods are provided for shutting down an
ExecutorService. The shutdown() method will allow previously submitted
tasks to execute before terminating, while the shutdownNow() method
prevents waiting tasks from starting and attempts to stop currently
executing tasks. Upon termination, an executor has no tasks actively
executing, no tasks awaiting execution, and no new tasks can be
submitted. An unused ExecutorService should be shut down to allow
reclamation of its resources.
Method submit extends base method Executor.execute(Runnable) by
creating and returning a Future that can be used to cancel execution
and/or wait for completion. Methods invokeAny and invokeAll perform
the most commonly useful forms of bulk execution, executing a
collection of tasks and then waiting for at least one, or all, to
complete.
ExecutorService executorService = Executors.newFixedThreadPool(maximumNumberOfThreads);
CompletionService completionService = new ExecutorCompletionService(executorService);
for (int i = 0; i < numberOfTasks; ++i) {
completionService.take();
}
executorService.shutdown();
Plus take a look at ThreadPoolExecutor
Since java provides more advanced threading API with concurrent package, You should have look into ExecutorService, which simplifies thread management mechanism.
Simple to solution to your problem.
Use Executors API to create thread pool
static ExecutorService newFixedThreadPool(int nThreads)
Creates a thread pool that reuses a fixed number of threads operating off a shared unbounded queue.
Use invokeAll to wait for all tasks to complete.
Sample code:
ExecutorService service = Executors.newFixedThreadPool(10);
List<MyCallable> futureList = new ArrayList<MyCallable>();
for ( int i=0; i<12; i++){
MyCallable myCallable = new MyCallable((long)i);
futureList.add(myCallable);
}
System.out.println("Start");
try{
List<Future<Long>> futures = service.invokeAll(futureList);
for(Future<Long> future : futures){
try{
System.out.println("future.isDone = " + future.isDone());
System.out.println("future: call ="+future.get());
}
catch(Exception err1){
err1.printStackTrace();
}
}
}catch(Exception err){
err.printStackTrace();
}
service.shutdown();
Refer to this related SE question for more details on achieving the same:
wait until all threads finish their work in java
I have a multithreaded application and I assign a unique name to each thread through setName() property. Now, I want functionality to get access to the threads directly with their corresponding name.
Somethings like the following function:
public Thread getThreadByName(String threadName) {
Thread __tmp = null;
Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
Thread[] threadArray = threadSet.toArray(new Thread[threadSet.size()]);
for (int i = 0; i < threadArray.length; i++) {
if (threadArray[i].getName().equals(threadName))
__tmp = threadArray[i];
}
return __tmp;
}
The above function checks all running threads and then returns the desired thread from the set of running threads. Maybe my desired thread is interrupted, then the above function won't work. Any ideas on how to incorporate that functionality?
An iteration of Pete's answer..
public Thread getThreadByName(String threadName) {
for (Thread t : Thread.getAllStackTraces().keySet()) {
if (t.getName().equals(threadName)) return t;
}
return null;
}
You can find all active threads using ThreadGroup:
Get your current thread's group
Work your way up the threadgroup hierarchy by calling ThreadGroup.getParent() until you find a group with a null parent.
Call ThreadGroup.enumerate() to find all threads on the system.
The value of doing this completely escapes me ... what will you possibly do with a named thread? Unless you're subclassing Thread when you should be implementing Runnable (which is sloppy programming to start with).
I like the HashMap idea best, but if you want to keep the Set, you can iterate over the Set, rather than going through the setup of converting to an array:
Iterator<Thread> i = threadSet.iterator();
while(i.hasNext()) {
Thread t = i.next();
if(t.getName().equals(threadName)) return t;
}
return null;
That's how I did it on the basis of this:
/*
MIGHT THROW NULL POINTER
*/
Thread getThreadByName(String name) {
// Get current Thread Group
ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parentThreadGroup;
while ((parentThreadGroup = threadGroup.getParent()) != null) {
threadGroup = parentThreadGroup;
}
// List all active Threads
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
int nAllocated = threadMXBean.getThreadCount();
int n = 0;
Thread[] threads;
do {
nAllocated *= 2;
threads = new Thread[nAllocated];
n = threadGroup.enumerate(threads, true);
} while (n == nAllocated);
threads = Arrays.copyOf(threads, n);
// Get Thread by name
for (Thread thread : threads) {
System.out.println(thread.getName());
if (thread.getName().equals(name)) {
return thread;
}
}
return null;
}
So let's say I'm creating and starting a bunch of threads in a for loop, that is being executed in the run method of a launcher thread. Let's also say that I want to be able to interrupt the launcher thread and all threads that the thread has created, and I do this through a button.
So something like this -
try{
for(int i = 0; i < n;i++){
Worker currThread = new Worker(someArgs);
workerThreads.add(currThread);
currThread.start();
}
} catch (InterruptedException e){
e.printStackTrace();
}
BUTTON-
public void actionPerformed(ActionEvent arg0) {
List<Worker> threads = launchThread.getWorkerThreads();
for(int i = 0; i < threads.size();i++){
threads.get(i).interrupt();
}
launchThread.interrupt();
}
Now, let's say that I want to make it so that the interrupts cannot occur at the same time as thread creation. I think a way to do this would be to construct a dummy object and put both pieces of code inside a lock
synchronized(dummyObject){
//thread creation or interruption code here (shown above)
}
Will this way work? I ask because I'm not sure how to test to see if it will.
Start the threads separately from creating them.
for(int i = 0; i < n; i++) {
Worker currThread = new Worker(someArgs);
workerThreads.add(currThread);
}
// later
for (Worker w : workerThreads) {
w.start();
}
If that's still not enough, your dummyObject synchronization should work just fine.
// You probably need to make this a (private final) field
Object lock = new Object();
// later
synchronized (lock) {
for(int i = 0; i < n; i++) {
Worker currThread = new Worker(someArgs);
workerThreads.add(currThread);
w.start();
}
}
// later still
public void actionPerformed(ActionEvent arg0) {
synchronized (lock) {
// interruption code here
}
}
The concept of synchronization remains the same however complicated are the underlying operations to be executed.
As you specified, there are two types of mutually exclusive tasks (thread creation and interruption). So locking is pretty much the canonical tool for the job.